xref: /freebsd/usr.sbin/ppp/nat_cmd.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1c39934eaSBrian Somers /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
31de7b4b8SPedro F. Giffuni  *
4de97d73dSBrian Somers  * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5057fee78SBrian Somers  *                    Brian Somers <brian@Awfulhak.org>
6057fee78SBrian Somers  * All rights reserved.
7057fee78SBrian Somers  *
8057fee78SBrian Somers  * Redistribution and use in source and binary forms, with or without
9057fee78SBrian Somers  * modification, are permitted provided that the following conditions
10057fee78SBrian Somers  * are met:
11057fee78SBrian Somers  * 1. Redistributions of source code must retain the above copyright
12057fee78SBrian Somers  *    notice, this list of conditions and the following disclaimer.
13057fee78SBrian Somers  * 2. Redistributions in binary form must reproduce the above copyright
14057fee78SBrian Somers  *    notice, this list of conditions and the following disclaimer in the
15057fee78SBrian Somers  *    documentation and/or other materials provided with the distribution.
16057fee78SBrian Somers  *
17057fee78SBrian Somers  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18057fee78SBrian Somers  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19057fee78SBrian Somers  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20057fee78SBrian Somers  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21057fee78SBrian Somers  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22057fee78SBrian Somers  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23057fee78SBrian Somers  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24057fee78SBrian Somers  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25057fee78SBrian Somers  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26057fee78SBrian Somers  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27057fee78SBrian Somers  * SUCH DAMAGE.
2875240ed1SBrian Somers  */
29f82fd828SBrian Somers 
30972a1bcfSBrian Somers #include <sys/param.h>
31f82fd828SBrian Somers #include <netinet/in.h>
32f82fd828SBrian Somers #include <arpa/inet.h>
3375240ed1SBrian Somers #include <netdb.h>
34615ad4f9SBrian Somers #include <netinet/in_systm.h>
35615ad4f9SBrian Somers #include <netinet/ip.h>
3630949fd4SBrian Somers #include <sys/socket.h>
37615ad4f9SBrian Somers #include <sys/un.h>
38f82fd828SBrian Somers 
396eafd353SBrian Somers #include <stdarg.h>
4075240ed1SBrian Somers #include <stdio.h>
4175240ed1SBrian Somers #include <stdlib.h>
4275240ed1SBrian Somers #include <string.h>
43d91d2861SBrian Somers #include <termios.h>
4475240ed1SBrian Somers 
4510e629b9SBrian Somers #ifdef LOCALNAT
467884358fSBrian Somers #include "alias.h"
4710e629b9SBrian Somers #else
4810e629b9SBrian Somers #include <alias.h>
491595bacdSBrian Somers #endif
5010e629b9SBrian Somers 
515d9e6103SBrian Somers #include "layer.h"
525d9e6103SBrian Somers #include "proto.h"
53c9e11a11SBrian Somers #include "defs.h"
54f82fd828SBrian Somers #include "command.h"
55b6e82f33SBrian Somers #include "log.h"
56f02c2029SBrian Somers #include "nat_cmd.h"
57d91d2861SBrian Somers #include "descriptor.h"
58d91d2861SBrian Somers #include "prompt.h"
59615ad4f9SBrian Somers #include "timer.h"
60615ad4f9SBrian Somers #include "fsm.h"
61615ad4f9SBrian Somers #include "slcompress.h"
62615ad4f9SBrian Somers #include "throughput.h"
63615ad4f9SBrian Somers #include "iplist.h"
645a72b6edSBrian Somers #include "mbuf.h"
65615ad4f9SBrian Somers #include "lqr.h"
66615ad4f9SBrian Somers #include "hdlc.h"
6730949fd4SBrian Somers #include "ncpaddr.h"
6830949fd4SBrian Somers #include "ip.h"
695a72b6edSBrian Somers #include "ipcp.h"
7030949fd4SBrian Somers #include "ipv6cp.h"
71615ad4f9SBrian Somers #include "lcp.h"
72615ad4f9SBrian Somers #include "ccp.h"
73615ad4f9SBrian Somers #include "link.h"
74615ad4f9SBrian Somers #include "mp.h"
75615ad4f9SBrian Somers #include "filter.h"
76972a1bcfSBrian Somers #ifndef NORADIUS
77972a1bcfSBrian Somers #include "radius.h"
78972a1bcfSBrian Somers #endif
7930949fd4SBrian Somers #include "ncp.h"
80615ad4f9SBrian Somers #include "bundle.h"
81f82fd828SBrian Somers 
82f82fd828SBrian Somers 
83323b15a1SBrian Somers #define NAT_EXTRABUF (13)
84323b15a1SBrian Somers 
85b6e82f33SBrian Somers static int StrToAddr(const char *, struct in_addr *);
86fe3094cdSBrian Somers static int StrToPortRange(const char *, u_short *, u_short *, const char *);
87fe3094cdSBrian Somers static int StrToAddrAndPort(const char *, struct in_addr *, u_short *,
88fe3094cdSBrian Somers                             u_short *, const char *);
89f82fd828SBrian Somers 
90a5625ae7SPaolo Pisati extern struct libalias *la;
91a5625ae7SPaolo Pisati 
929afe6bdaSBrian Somers static void
lowhigh(u_short * a,u_short * b)939afe6bdaSBrian Somers lowhigh(u_short *a, u_short *b)
949afe6bdaSBrian Somers {
959afe6bdaSBrian Somers   if (a > b) {
969afe6bdaSBrian Somers     u_short c;
979afe6bdaSBrian Somers 
989afe6bdaSBrian Somers     c = *b;
999afe6bdaSBrian Somers     *b = *a;
1009afe6bdaSBrian Somers     *a = c;
1019afe6bdaSBrian Somers   }
1029afe6bdaSBrian Somers }
103f82fd828SBrian Somers 
104f82fd828SBrian Somers int
nat_RedirectPort(struct cmdargs const * arg)10567b072f7SBrian Somers nat_RedirectPort(struct cmdargs const *arg)
106f82fd828SBrian Somers {
10767b072f7SBrian Somers   if (!arg->bundle->NatEnabled) {
108d91d2861SBrian Somers     prompt_Printf(arg->prompt, "Alias not enabled\n");
1098511968cSBrian Somers     return 1;
1109afe6bdaSBrian Somers   } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) {
111f82fd828SBrian Somers     char proto_constant;
112b6e82f33SBrian Somers     const char *proto;
1139afe6bdaSBrian Somers     struct in_addr localaddr;
1149afe6bdaSBrian Somers     u_short hlocalport, llocalport;
1159afe6bdaSBrian Somers     struct in_addr aliasaddr;
1169afe6bdaSBrian Somers     u_short haliasport, laliasport;
1179afe6bdaSBrian Somers     struct in_addr remoteaddr;
1189afe6bdaSBrian Somers     u_short hremoteport, lremoteport;
119f82fd828SBrian Somers     struct alias_link *link;
1209afe6bdaSBrian Somers     int error;
121f82fd828SBrian Somers 
122d91d2861SBrian Somers     proto = arg->argv[arg->argn];
1236ed9fb2fSBrian Somers     if (strcmp(proto, "tcp") == 0) {
124f82fd828SBrian Somers       proto_constant = IPPROTO_TCP;
1256ed9fb2fSBrian Somers     } else if (strcmp(proto, "udp") == 0) {
126f82fd828SBrian Somers       proto_constant = IPPROTO_UDP;
1276ed9fb2fSBrian Somers     } else {
128d91d2861SBrian Somers       prompt_Printf(arg->prompt, "port redirect: protocol must be"
129d91d2861SBrian Somers                     " tcp or udp\n");
130fe3094cdSBrian Somers       return -1;
131f82fd828SBrian Somers     }
132f82fd828SBrian Somers 
1339afe6bdaSBrian Somers     error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport,
134fe3094cdSBrian Somers                              &hlocalport, proto);
135fe3094cdSBrian Somers     if (error) {
13667b072f7SBrian Somers       prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n");
137fe3094cdSBrian Somers       return -1;
138fe3094cdSBrian Somers     }
1399afe6bdaSBrian Somers 
140fe3094cdSBrian Somers     error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport,
141d91d2861SBrian Somers                            proto);
1426ed9fb2fSBrian Somers     if (error) {
14367b072f7SBrian Somers       prompt_Printf(arg->prompt, "nat port: error reading alias port\n");
144fe3094cdSBrian Somers       return -1;
145f82fd828SBrian Somers     }
1469afe6bdaSBrian Somers     aliasaddr.s_addr = INADDR_ANY;
147f82fd828SBrian Somers 
1489afe6bdaSBrian Somers     if (arg->argc == arg->argn + 4) {
1499afe6bdaSBrian Somers       error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr,
1509afe6bdaSBrian Somers                                &lremoteport, &hremoteport, proto);
1519afe6bdaSBrian Somers       if (error) {
15267b072f7SBrian Somers         prompt_Printf(arg->prompt, "nat port: error reading "
1539afe6bdaSBrian Somers                       "remoteaddr:port\n");
1549afe6bdaSBrian Somers         return -1;
1559afe6bdaSBrian Somers       }
1569afe6bdaSBrian Somers     } else {
1579afe6bdaSBrian Somers       remoteaddr.s_addr = INADDR_ANY;
1589afe6bdaSBrian Somers       lremoteport = hremoteport = 0;
159fe3094cdSBrian Somers     }
160fe3094cdSBrian Somers 
1619afe6bdaSBrian Somers     lowhigh(&llocalport, &hlocalport);
1629afe6bdaSBrian Somers     lowhigh(&laliasport, &haliasport);
1639afe6bdaSBrian Somers     lowhigh(&lremoteport, &hremoteport);
164fe3094cdSBrian Somers 
165fe3094cdSBrian Somers     if (haliasport - laliasport != hlocalport - llocalport) {
16667b072f7SBrian Somers       prompt_Printf(arg->prompt, "nat port: local & alias port ranges "
1679afe6bdaSBrian Somers                     "are not equal\n");
168fe3094cdSBrian Somers       return -1;
169fe3094cdSBrian Somers     }
170fe3094cdSBrian Somers 
1719afe6bdaSBrian Somers     if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) {
17267b072f7SBrian Somers       prompt_Printf(arg->prompt, "nat port: local & remote port ranges "
1739afe6bdaSBrian Somers                     "are not equal\n");
1749afe6bdaSBrian Somers       return -1;
1759afe6bdaSBrian Somers     }
1769afe6bdaSBrian Somers 
1778e41399cSBrian Somers     do {
178a5625ae7SPaolo Pisati       link = LibAliasRedirectPort(la, localaddr, htons(llocalport),
1799afe6bdaSBrian Somers 				     remoteaddr, htons(lremoteport),
1809afe6bdaSBrian Somers                                      aliasaddr, htons(laliasport),
181f82fd828SBrian Somers 				     proto_constant);
182f82fd828SBrian Somers 
183fe3094cdSBrian Somers       if (link == NULL) {
18467b072f7SBrian Somers         prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport,
1859afe6bdaSBrian Somers                       error);
186fe3094cdSBrian Somers         return 1;
187fe3094cdSBrian Somers       }
1889afe6bdaSBrian Somers       llocalport++;
1899afe6bdaSBrian Somers       if (hremoteport)
1909afe6bdaSBrian Somers         lremoteport++;
1918e41399cSBrian Somers     } while (laliasport++ < haliasport);
1926ed9fb2fSBrian Somers 
1938511968cSBrian Somers     return 0;
194f82fd828SBrian Somers   }
195f82fd828SBrian Somers 
1969afe6bdaSBrian Somers   return -1;
1979afe6bdaSBrian Somers }
1989afe6bdaSBrian Somers 
199f82fd828SBrian Somers 
200f82fd828SBrian Somers int
nat_RedirectAddr(struct cmdargs const * arg)20167b072f7SBrian Somers nat_RedirectAddr(struct cmdargs const *arg)
202f82fd828SBrian Somers {
20367b072f7SBrian Somers   if (!arg->bundle->NatEnabled) {
20467b072f7SBrian Somers     prompt_Printf(arg->prompt, "nat not enabled\n");
2058511968cSBrian Somers     return 1;
206d91d2861SBrian Somers   } else if (arg->argc == arg->argn+2) {
207f82fd828SBrian Somers     int error;
2089afe6bdaSBrian Somers     struct in_addr localaddr, aliasaddr;
209f82fd828SBrian Somers     struct alias_link *link;
210f82fd828SBrian Somers 
2119afe6bdaSBrian Somers     error = StrToAddr(arg->argv[arg->argn], &localaddr);
2126ed9fb2fSBrian Somers     if (error) {
213d91d2861SBrian Somers       prompt_Printf(arg->prompt, "address redirect: invalid local address\n");
214f82fd828SBrian Somers       return 1;
215f82fd828SBrian Somers     }
2169afe6bdaSBrian Somers     error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr);
2176ed9fb2fSBrian Somers     if (error) {
218d91d2861SBrian Somers       prompt_Printf(arg->prompt, "address redirect: invalid alias address\n");
219d3974088SDag-Erling Smørgrav       prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
220d91d2861SBrian Somers                     arg->cmd->syntax);
221f82fd828SBrian Somers       return 1;
222f82fd828SBrian Somers     }
223a5625ae7SPaolo Pisati     link = LibAliasRedirectAddr(la, localaddr, aliasaddr);
224d91d2861SBrian Somers     if (link == NULL) {
225d91d2861SBrian Somers       prompt_Printf(arg->prompt, "address redirect: packet aliasing"
226d91d2861SBrian Somers                     " engine error\n");
227d3974088SDag-Erling Smørgrav       prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
228d91d2861SBrian Somers                     arg->cmd->syntax);
229f82fd828SBrian Somers     }
2308511968cSBrian Somers   } else
2318511968cSBrian Somers     return -1;
2326ed9fb2fSBrian Somers 
2338511968cSBrian Somers   return 0;
234f82fd828SBrian Somers }
235f82fd828SBrian Somers 
236f82fd828SBrian Somers 
23788298994SBrian Somers int
nat_RedirectProto(struct cmdargs const * arg)23888298994SBrian Somers nat_RedirectProto(struct cmdargs const *arg)
23988298994SBrian Somers {
24088298994SBrian Somers   if (!arg->bundle->NatEnabled) {
24188298994SBrian Somers     prompt_Printf(arg->prompt, "nat not enabled\n");
24288298994SBrian Somers     return 1;
24388298994SBrian Somers   } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) {
24488298994SBrian Somers     struct in_addr localIP, publicIP, remoteIP;
24588298994SBrian Somers     struct alias_link *link;
24688298994SBrian Somers     struct protoent *pe;
247057f1760SBrian Somers     int error;
248057f1760SBrian Somers     unsigned len;
24988298994SBrian Somers 
25088298994SBrian Somers     len = strlen(arg->argv[arg->argn]);
25188298994SBrian Somers     if (len == 0) {
25288298994SBrian Somers       prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n");
25388298994SBrian Somers       return 1;
25488298994SBrian Somers     }
25588298994SBrian Somers     if (strspn(arg->argv[arg->argn], "01234567") == len)
25688298994SBrian Somers       pe = getprotobynumber(atoi(arg->argv[arg->argn]));
25788298994SBrian Somers     else
25888298994SBrian Somers       pe = getprotobyname(arg->argv[arg->argn]);
25988298994SBrian Somers     if (pe == NULL) {
26088298994SBrian Somers       prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n");
26188298994SBrian Somers       return 1;
26288298994SBrian Somers     }
26388298994SBrian Somers 
26488298994SBrian Somers     error = StrToAddr(arg->argv[arg->argn + 1], &localIP);
26588298994SBrian Somers     if (error) {
26688298994SBrian Somers       prompt_Printf(arg->prompt, "proto redirect: invalid src address\n");
26788298994SBrian Somers       return 1;
26888298994SBrian Somers     }
26988298994SBrian Somers 
27088298994SBrian Somers     if (arg->argc >= arg->argn + 3) {
27188298994SBrian Somers       error = StrToAddr(arg->argv[arg->argn + 2], &publicIP);
27288298994SBrian Somers       if (error) {
27388298994SBrian Somers         prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n");
274d3974088SDag-Erling Smørgrav         prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
27588298994SBrian Somers                       arg->cmd->syntax);
27688298994SBrian Somers         return 1;
27788298994SBrian Somers       }
27888298994SBrian Somers     } else
27988298994SBrian Somers       publicIP.s_addr = INADDR_ANY;
28088298994SBrian Somers 
28188298994SBrian Somers     if (arg->argc == arg->argn + 4) {
28288298994SBrian Somers       error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP);
28388298994SBrian Somers       if (error) {
28488298994SBrian Somers         prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n");
285d3974088SDag-Erling Smørgrav         prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
28688298994SBrian Somers                       arg->cmd->syntax);
28788298994SBrian Somers         return 1;
28888298994SBrian Somers       }
28988298994SBrian Somers     } else
29088298994SBrian Somers       remoteIP.s_addr = INADDR_ANY;
29188298994SBrian Somers 
292a5625ae7SPaolo Pisati     link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto);
29388298994SBrian Somers     if (link == NULL) {
29488298994SBrian Somers       prompt_Printf(arg->prompt, "proto redirect: packet aliasing"
29588298994SBrian Somers                     " engine error\n");
296d3974088SDag-Erling Smørgrav       prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
29788298994SBrian Somers                     arg->cmd->syntax);
29888298994SBrian Somers     }
29988298994SBrian Somers   } else
30088298994SBrian Somers     return -1;
30188298994SBrian Somers 
30288298994SBrian Somers   return 0;
30388298994SBrian Somers }
30488298994SBrian Somers 
30588298994SBrian Somers 
306f82fd828SBrian Somers static int
StrToAddr(const char * str,struct in_addr * addr)307b6e82f33SBrian Somers StrToAddr(const char *str, struct in_addr *addr)
308f82fd828SBrian Somers {
309f82fd828SBrian Somers   struct hostent *hp;
310f82fd828SBrian Somers 
311f82fd828SBrian Somers   if (inet_aton(str, addr))
312f82fd828SBrian Somers     return 0;
313f82fd828SBrian Somers 
314f82fd828SBrian Somers   hp = gethostbyname(str);
315944f7098SBrian Somers   if (!hp) {
316d91d2861SBrian Somers     log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str);
317f82fd828SBrian Somers     return -1;
318f82fd828SBrian Somers   }
319f82fd828SBrian Somers   *addr = *((struct in_addr *) hp->h_addr);
320f82fd828SBrian Somers   return 0;
321f82fd828SBrian Somers }
322f82fd828SBrian Somers 
323f82fd828SBrian Somers 
324f82fd828SBrian Somers static int
StrToPort(const char * str,u_short * port,const char * proto)325b6e82f33SBrian Somers StrToPort(const char *str, u_short *port, const char *proto)
326f82fd828SBrian Somers {
327f82fd828SBrian Somers   struct servent *sp;
328f82fd828SBrian Somers   char *end;
329f82fd828SBrian Somers 
330fe3094cdSBrian Somers   *port = strtol(str, &end, 10);
331fe3094cdSBrian Somers   if (*end != '\0') {
332f82fd828SBrian Somers     sp = getservbyname(str, proto);
333fe3094cdSBrian Somers     if (sp == NULL) {
334d91d2861SBrian Somers       log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n",
335f82fd828SBrian Somers 	        str, proto);
336f82fd828SBrian Somers       return -1;
337f82fd828SBrian Somers     }
338fe3094cdSBrian Somers     *port = ntohs(sp->s_port);
339fe3094cdSBrian Somers   }
340fe3094cdSBrian Somers 
341f82fd828SBrian Somers   return 0;
342f82fd828SBrian Somers }
343f82fd828SBrian Somers 
344fe3094cdSBrian Somers static int
StrToPortRange(const char * str,u_short * low,u_short * high,const char * proto)345fe3094cdSBrian Somers StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto)
346fe3094cdSBrian Somers {
347fe3094cdSBrian Somers   char *minus;
348fe3094cdSBrian Somers   int res;
349fe3094cdSBrian Somers 
350fe3094cdSBrian Somers   minus = strchr(str, '-');
351fe3094cdSBrian Somers   if (minus)
352fe3094cdSBrian Somers     *minus = '\0';		/* Cheat the const-ness ! */
353fe3094cdSBrian Somers 
354fe3094cdSBrian Somers   res = StrToPort(str, low, proto);
355fe3094cdSBrian Somers 
356fe3094cdSBrian Somers   if (minus)
357fe3094cdSBrian Somers     *minus = '-';		/* Cheat the const-ness ! */
358fe3094cdSBrian Somers 
359fe3094cdSBrian Somers   if (res == 0) {
360fe3094cdSBrian Somers     if (minus)
361fe3094cdSBrian Somers       res = StrToPort(minus + 1, high, proto);
362fe3094cdSBrian Somers     else
363fe3094cdSBrian Somers       *high = *low;
364fe3094cdSBrian Somers   }
365fe3094cdSBrian Somers 
366fe3094cdSBrian Somers   return res;
367fe3094cdSBrian Somers }
368f82fd828SBrian Somers 
369b6e82f33SBrian Somers static int
StrToAddrAndPort(const char * str,struct in_addr * addr,u_short * low,u_short * high,const char * proto)370fe3094cdSBrian Somers StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low,
371fe3094cdSBrian Somers                  u_short *high, const char *proto)
372f82fd828SBrian Somers {
373b6e82f33SBrian Somers   char *colon;
374b6e82f33SBrian Somers   int res;
375f82fd828SBrian Somers 
376b6e82f33SBrian Somers   colon = strchr(str, ':');
377b6e82f33SBrian Somers   if (!colon) {
378d91d2861SBrian Somers     log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str);
379f82fd828SBrian Somers     return -1;
380f82fd828SBrian Somers   }
381f82fd828SBrian Somers 
382b6e82f33SBrian Somers   *colon = '\0';		/* Cheat the const-ness ! */
383b6e82f33SBrian Somers   res = StrToAddr(str, addr);
384b6e82f33SBrian Somers   *colon = ':';			/* Cheat the const-ness ! */
385b6e82f33SBrian Somers   if (res != 0)
386f82fd828SBrian Somers     return -1;
387f82fd828SBrian Somers 
388fe3094cdSBrian Somers   return StrToPortRange(colon + 1, low, high, proto);
389f82fd828SBrian Somers }
390d318fe8eSBrian Somers 
391d318fe8eSBrian Somers int
nat_ProxyRule(struct cmdargs const * arg)39267b072f7SBrian Somers nat_ProxyRule(struct cmdargs const *arg)
393d318fe8eSBrian Somers {
394d318fe8eSBrian Somers   char cmd[LINE_LEN];
395d318fe8eSBrian Somers   int f, pos;
396d318fe8eSBrian Somers   size_t len;
397d318fe8eSBrian Somers 
398d318fe8eSBrian Somers   if (arg->argn >= arg->argc)
399d318fe8eSBrian Somers     return -1;
400d318fe8eSBrian Somers 
401d318fe8eSBrian Somers   for (f = arg->argn, pos = 0; f < arg->argc; f++) {
402d318fe8eSBrian Somers     len = strlen(arg->argv[f]);
40349ed07a3SBrian Somers     if (sizeof cmd - pos < len + (len ? 1 : 0))
404d318fe8eSBrian Somers       break;
40549ed07a3SBrian Somers     if (len)
406d318fe8eSBrian Somers       cmd[pos++] = ' ';
407d318fe8eSBrian Somers     strcpy(cmd + pos, arg->argv[f]);
408d318fe8eSBrian Somers     pos += len;
409d318fe8eSBrian Somers   }
410d318fe8eSBrian Somers 
411a5625ae7SPaolo Pisati   return LibAliasProxyRule(la, cmd);
412d318fe8eSBrian Somers }
41350a63ab9SBrian Somers 
41450a63ab9SBrian Somers int
nat_SetTarget(struct cmdargs const * arg)415b7d8533cSBrian Somers nat_SetTarget(struct cmdargs const *arg)
416b7d8533cSBrian Somers {
417b7d8533cSBrian Somers   struct in_addr addr;
418b7d8533cSBrian Somers 
419b7d8533cSBrian Somers   if (arg->argc == arg->argn) {
42044d127bcSBrian Somers     addr.s_addr = INADDR_ANY;
421a5625ae7SPaolo Pisati     LibAliasSetTarget(la, addr);
422b7d8533cSBrian Somers     return 0;
423b7d8533cSBrian Somers   }
424b7d8533cSBrian Somers 
425b7d8533cSBrian Somers   if (arg->argc != arg->argn + 1)
426b7d8533cSBrian Somers     return -1;
427b7d8533cSBrian Somers 
4287d7b90c7SBrian Somers   if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) {
42944d127bcSBrian Somers     addr.s_addr = INADDR_ANY;
430a5625ae7SPaolo Pisati     LibAliasSetTarget(la, addr);
43144d127bcSBrian Somers     return 0;
43244d127bcSBrian Somers   }
43344d127bcSBrian Somers 
434b7d8533cSBrian Somers   addr = GetIpAddr(arg->argv[arg->argn]);
435b7d8533cSBrian Somers   if (addr.s_addr == INADDR_NONE) {
436b7d8533cSBrian Somers     log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]);
437b7d8533cSBrian Somers     return 1;
438b7d8533cSBrian Somers   }
439b7d8533cSBrian Somers 
440a5625ae7SPaolo Pisati   LibAliasSetTarget(la, addr);
441b7d8533cSBrian Somers   return 0;
442b7d8533cSBrian Somers }
443b7d8533cSBrian Somers 
444686e8c8bSBrian Somers #ifndef NO_FW_PUNCH
445686e8c8bSBrian Somers int
nat_PunchFW(struct cmdargs const * arg)446686e8c8bSBrian Somers nat_PunchFW(struct cmdargs const *arg)
447686e8c8bSBrian Somers {
448686e8c8bSBrian Somers   char *end;
449686e8c8bSBrian Somers   long base, count;
450686e8c8bSBrian Somers 
451686e8c8bSBrian Somers   if (arg->argc == arg->argn) {
452a5625ae7SPaolo Pisati     LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW);
453686e8c8bSBrian Somers     return 0;
454686e8c8bSBrian Somers   }
455686e8c8bSBrian Somers 
456686e8c8bSBrian Somers   if (arg->argc != arg->argn + 2)
457686e8c8bSBrian Somers     return -1;
458686e8c8bSBrian Somers 
459686e8c8bSBrian Somers   base = strtol(arg->argv[arg->argn], &end, 10);
460686e8c8bSBrian Somers   if (*end != '\0' || base < 0)
461686e8c8bSBrian Somers     return -1;
462686e8c8bSBrian Somers 
463686e8c8bSBrian Somers   count = strtol(arg->argv[arg->argn + 1], &end, 10);
464686e8c8bSBrian Somers   if (*end != '\0' || count < 0)
465686e8c8bSBrian Somers     return -1;
466686e8c8bSBrian Somers 
467a5625ae7SPaolo Pisati   LibAliasSetFWBase(la, base, count);
468a5625ae7SPaolo Pisati   LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
469686e8c8bSBrian Somers 
470686e8c8bSBrian Somers   return 0;
471686e8c8bSBrian Somers }
472686e8c8bSBrian Somers #endif
473686e8c8bSBrian Somers 
474b07fbc17SJoe Marcus Clarke int
nat_SkinnyPort(struct cmdargs const * arg)475b07fbc17SJoe Marcus Clarke nat_SkinnyPort(struct cmdargs const *arg)
476b07fbc17SJoe Marcus Clarke {
477b07fbc17SJoe Marcus Clarke   char *end;
478b07fbc17SJoe Marcus Clarke   long port;
479b07fbc17SJoe Marcus Clarke 
480b07fbc17SJoe Marcus Clarke   if (arg->argc == arg->argn) {
481a5625ae7SPaolo Pisati     LibAliasSetSkinnyPort(la, 0);
482b07fbc17SJoe Marcus Clarke     return 0;
483b07fbc17SJoe Marcus Clarke   }
484b07fbc17SJoe Marcus Clarke 
485b07fbc17SJoe Marcus Clarke   if (arg->argc != arg->argn + 1)
486b07fbc17SJoe Marcus Clarke     return -1;
487b07fbc17SJoe Marcus Clarke 
488b07fbc17SJoe Marcus Clarke   port = strtol(arg->argv[arg->argn], &end, 10);
489b07fbc17SJoe Marcus Clarke   if (*end != '\0' || port < 0)
490b07fbc17SJoe Marcus Clarke     return -1;
491b07fbc17SJoe Marcus Clarke 
492a5625ae7SPaolo Pisati   LibAliasSetSkinnyPort(la, port);
493b07fbc17SJoe Marcus Clarke 
494b07fbc17SJoe Marcus Clarke   return 0;
495b07fbc17SJoe Marcus Clarke }
496b07fbc17SJoe Marcus Clarke 
4975d9e6103SBrian Somers static struct mbuf *
nat_LayerPush(struct bundle * bundle,struct link * l __unused,struct mbuf * bp,int pri __unused,u_short * proto)498057f1760SBrian Somers nat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp,
499057f1760SBrian Somers                 int pri __unused, u_short *proto)
5005d9e6103SBrian Somers {
50167b072f7SBrian Somers   if (!bundle->NatEnabled || *proto != PROTO_IP)
5025d9e6103SBrian Somers     return bp;
5035d9e6103SBrian Somers 
50467b072f7SBrian Somers   log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n");
50526af0ae9SBrian Somers   m_settype(bp, MB_NATOUT);
506323b15a1SBrian Somers   /* Ensure there's a bit of extra buffer for the NAT code... */
507323b15a1SBrian Somers   bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF));
508a5625ae7SPaolo Pisati   LibAliasOut(la, MBUF_CTOP(bp), bp->m_len);
509323b15a1SBrian Somers   bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
5105d9e6103SBrian Somers 
5115d9e6103SBrian Somers   return bp;
5125d9e6103SBrian Somers }
5135d9e6103SBrian Somers 
5145d9e6103SBrian Somers static struct mbuf *
nat_LayerPull(struct bundle * bundle,struct link * l __unused,struct mbuf * bp,u_short * proto)515057f1760SBrian Somers nat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp,
5165d9e6103SBrian Somers                 u_short *proto)
5175d9e6103SBrian Somers {
518a1f961d3SBrian Somers   static int gfrags;
519a1f961d3SBrian Somers   int ret, len, nfrags;
5205d9e6103SBrian Somers   struct mbuf **last;
5215d9e6103SBrian Somers   char *fptr;
5225d9e6103SBrian Somers 
52367b072f7SBrian Somers   if (!bundle->NatEnabled || *proto != PROTO_IP)
5245d9e6103SBrian Somers     return bp;
5255d9e6103SBrian Somers 
52667b072f7SBrian Somers   log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n");
52726af0ae9SBrian Somers   m_settype(bp, MB_NATIN);
528323b15a1SBrian Somers   /* Ensure there's a bit of extra buffer for the NAT code... */
529323b15a1SBrian Somers   bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF));
530a5625ae7SPaolo Pisati   ret = LibAliasIn(la, MBUF_CTOP(bp), bp->m_len);
5315d9e6103SBrian Somers 
532eb598e08SBrian Somers   bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
53326af0ae9SBrian Somers   if (bp->m_len > MAX_MRU) {
534209dc102SBrian Somers     log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n",
535209dc102SBrian Somers                (unsigned long)bp->m_len);
53626af0ae9SBrian Somers     m_freem(bp);
5375d9e6103SBrian Somers     return NULL;
5385d9e6103SBrian Somers   }
5395d9e6103SBrian Somers 
5405d9e6103SBrian Somers   switch (ret) {
5415d9e6103SBrian Somers     case PKT_ALIAS_OK:
5425d9e6103SBrian Somers       break;
5435d9e6103SBrian Somers 
5445d9e6103SBrian Somers     case PKT_ALIAS_UNRESOLVED_FRAGMENT:
5455d9e6103SBrian Somers       /* Save the data for later */
5465d604c11SBrian Somers       if ((fptr = malloc(bp->m_len)) == NULL) {
5475d604c11SBrian Somers 	log_Printf(LogWARN, "nat_LayerPull: Dropped unresolved fragment -"
5485d604c11SBrian Somers 		   " out of memory!\n");
5495d604c11SBrian Somers 	m_freem(bp);
5505d604c11SBrian Somers 	bp = NULL;
5515d604c11SBrian Somers       } else {
55226af0ae9SBrian Somers 	bp = mbuf_Read(bp, fptr, bp->m_len);
553a5625ae7SPaolo Pisati 	LibAliasSaveFragment(la, fptr);
554a1f961d3SBrian Somers 	log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n",
555a1f961d3SBrian Somers 		   (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags);
5565d604c11SBrian Somers       }
5575d9e6103SBrian Somers       break;
5585d9e6103SBrian Somers 
5595d9e6103SBrian Somers     case PKT_ALIAS_FOUND_HEADER_FRAGMENT:
5605d9e6103SBrian Somers       /* Fetch all the saved fragments and chain them on the end of `bp' */
56126af0ae9SBrian Somers       last = &bp->m_nextpkt;
562a1f961d3SBrian Somers       nfrags = 0;
563a5625ae7SPaolo Pisati       while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) {
564a1f961d3SBrian Somers         nfrags++;
565a5625ae7SPaolo Pisati         LibAliasFragmentIn(la, MBUF_CTOP(bp), fptr);
566ef8fcfa7SBrian Somers         len = ntohs(((struct ip *)fptr)->ip_len);
56726af0ae9SBrian Somers         *last = m_get(len, MB_NATIN);
568ef8fcfa7SBrian Somers         memcpy(MBUF_CTOP(*last), fptr, len);
5695d9e6103SBrian Somers         free(fptr);
57026af0ae9SBrian Somers         last = &(*last)->m_nextpkt;
5715d9e6103SBrian Somers       }
572a1f961d3SBrian Somers       gfrags -= nfrags;
573a1f961d3SBrian Somers       log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no"
574a1f961d3SBrian Somers                  "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id,
575a1f961d3SBrian Somers                  nfrags, gfrags);
5765d9e6103SBrian Somers       break;
5775d9e6103SBrian Somers 
578b565321aSBrian Somers     case PKT_ALIAS_IGNORED:
579a5625ae7SPaolo Pisati       if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) {
580cf881f54SBrian Somers         log_Printf(LogTCPIP, "NAT engine denied data:\n");
581cf881f54SBrian Somers         m_freem(bp);
582cf881f54SBrian Somers         bp = NULL;
583cf881f54SBrian Somers       } else if (log_IsKept(LogTCPIP)) {
584b565321aSBrian Somers         log_Printf(LogTCPIP, "NAT engine ignored data:\n");
58530949fd4SBrian Somers         PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL,
58630949fd4SBrian Somers                     NULL, NULL);
587b565321aSBrian Somers       }
588b565321aSBrian Somers       break;
589b565321aSBrian Somers 
5905d9e6103SBrian Somers     default:
5910e20b877SBrian Somers       log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret);
59226af0ae9SBrian Somers       m_freem(bp);
5935d9e6103SBrian Somers       bp = NULL;
5945d9e6103SBrian Somers       break;
5955d9e6103SBrian Somers   }
5965d9e6103SBrian Somers 
5975d9e6103SBrian Somers   return bp;
5985d9e6103SBrian Somers }
5995d9e6103SBrian Somers 
60067b072f7SBrian Somers struct layer natlayer =
60167b072f7SBrian Somers   { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull };
602