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