1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2001 Charles Mott <cm@linktel.net>
5 * Brian Somers <brian@Awfulhak.org>
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
33 #include <netdb.h>
34 #include <netinet/in_systm.h>
35 #include <netinet/ip.h>
36 #include <sys/socket.h>
37 #include <sys/un.h>
38
39 #include <stdarg.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <termios.h>
44
45 #ifdef LOCALNAT
46 #include "alias.h"
47 #else
48 #include <alias.h>
49 #endif
50
51 #include "layer.h"
52 #include "proto.h"
53 #include "defs.h"
54 #include "command.h"
55 #include "log.h"
56 #include "nat_cmd.h"
57 #include "descriptor.h"
58 #include "prompt.h"
59 #include "timer.h"
60 #include "fsm.h"
61 #include "slcompress.h"
62 #include "throughput.h"
63 #include "iplist.h"
64 #include "mbuf.h"
65 #include "lqr.h"
66 #include "hdlc.h"
67 #include "ncpaddr.h"
68 #include "ip.h"
69 #include "ipcp.h"
70 #include "ipv6cp.h"
71 #include "lcp.h"
72 #include "ccp.h"
73 #include "link.h"
74 #include "mp.h"
75 #include "filter.h"
76 #ifndef NORADIUS
77 #include "radius.h"
78 #endif
79 #include "ncp.h"
80 #include "bundle.h"
81
82
83 #define NAT_EXTRABUF (13)
84
85 static int StrToAddr(const char *, struct in_addr *);
86 static int StrToPortRange(const char *, u_short *, u_short *, const char *);
87 static int StrToAddrAndPort(const char *, struct in_addr *, u_short *,
88 u_short *, const char *);
89
90 extern struct libalias *la;
91
92 static void
lowhigh(u_short * a,u_short * b)93 lowhigh(u_short *a, u_short *b)
94 {
95 if (a > b) {
96 u_short c;
97
98 c = *b;
99 *b = *a;
100 *a = c;
101 }
102 }
103
104 int
nat_RedirectPort(struct cmdargs const * arg)105 nat_RedirectPort(struct cmdargs const *arg)
106 {
107 if (!arg->bundle->NatEnabled) {
108 prompt_Printf(arg->prompt, "Alias not enabled\n");
109 return 1;
110 } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) {
111 char proto_constant;
112 const char *proto;
113 struct in_addr localaddr;
114 u_short hlocalport, llocalport;
115 struct in_addr aliasaddr;
116 u_short haliasport, laliasport;
117 struct in_addr remoteaddr;
118 u_short hremoteport, lremoteport;
119 struct alias_link *link;
120 int error;
121
122 proto = arg->argv[arg->argn];
123 if (strcmp(proto, "tcp") == 0) {
124 proto_constant = IPPROTO_TCP;
125 } else if (strcmp(proto, "udp") == 0) {
126 proto_constant = IPPROTO_UDP;
127 } else {
128 prompt_Printf(arg->prompt, "port redirect: protocol must be"
129 " tcp or udp\n");
130 return -1;
131 }
132
133 error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport,
134 &hlocalport, proto);
135 if (error) {
136 prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n");
137 return -1;
138 }
139
140 error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport,
141 proto);
142 if (error) {
143 prompt_Printf(arg->prompt, "nat port: error reading alias port\n");
144 return -1;
145 }
146 aliasaddr.s_addr = INADDR_ANY;
147
148 if (arg->argc == arg->argn + 4) {
149 error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr,
150 &lremoteport, &hremoteport, proto);
151 if (error) {
152 prompt_Printf(arg->prompt, "nat port: error reading "
153 "remoteaddr:port\n");
154 return -1;
155 }
156 } else {
157 remoteaddr.s_addr = INADDR_ANY;
158 lremoteport = hremoteport = 0;
159 }
160
161 lowhigh(&llocalport, &hlocalport);
162 lowhigh(&laliasport, &haliasport);
163 lowhigh(&lremoteport, &hremoteport);
164
165 if (haliasport - laliasport != hlocalport - llocalport) {
166 prompt_Printf(arg->prompt, "nat port: local & alias port ranges "
167 "are not equal\n");
168 return -1;
169 }
170
171 if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) {
172 prompt_Printf(arg->prompt, "nat port: local & remote port ranges "
173 "are not equal\n");
174 return -1;
175 }
176
177 do {
178 link = LibAliasRedirectPort(la, localaddr, htons(llocalport),
179 remoteaddr, htons(lremoteport),
180 aliasaddr, htons(laliasport),
181 proto_constant);
182
183 if (link == NULL) {
184 prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport,
185 error);
186 return 1;
187 }
188 llocalport++;
189 if (hremoteport)
190 lremoteport++;
191 } while (laliasport++ < haliasport);
192
193 return 0;
194 }
195
196 return -1;
197 }
198
199
200 int
nat_RedirectAddr(struct cmdargs const * arg)201 nat_RedirectAddr(struct cmdargs const *arg)
202 {
203 if (!arg->bundle->NatEnabled) {
204 prompt_Printf(arg->prompt, "nat not enabled\n");
205 return 1;
206 } else if (arg->argc == arg->argn+2) {
207 int error;
208 struct in_addr localaddr, aliasaddr;
209 struct alias_link *link;
210
211 error = StrToAddr(arg->argv[arg->argn], &localaddr);
212 if (error) {
213 prompt_Printf(arg->prompt, "address redirect: invalid local address\n");
214 return 1;
215 }
216 error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr);
217 if (error) {
218 prompt_Printf(arg->prompt, "address redirect: invalid alias address\n");
219 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
220 arg->cmd->syntax);
221 return 1;
222 }
223 link = LibAliasRedirectAddr(la, localaddr, aliasaddr);
224 if (link == NULL) {
225 prompt_Printf(arg->prompt, "address redirect: packet aliasing"
226 " engine error\n");
227 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
228 arg->cmd->syntax);
229 }
230 } else
231 return -1;
232
233 return 0;
234 }
235
236
237 int
nat_RedirectProto(struct cmdargs const * arg)238 nat_RedirectProto(struct cmdargs const *arg)
239 {
240 if (!arg->bundle->NatEnabled) {
241 prompt_Printf(arg->prompt, "nat not enabled\n");
242 return 1;
243 } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) {
244 struct in_addr localIP, publicIP, remoteIP;
245 struct alias_link *link;
246 struct protoent *pe;
247 int error;
248 unsigned len;
249
250 len = strlen(arg->argv[arg->argn]);
251 if (len == 0) {
252 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n");
253 return 1;
254 }
255 if (strspn(arg->argv[arg->argn], "01234567") == len)
256 pe = getprotobynumber(atoi(arg->argv[arg->argn]));
257 else
258 pe = getprotobyname(arg->argv[arg->argn]);
259 if (pe == NULL) {
260 prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n");
261 return 1;
262 }
263
264 error = StrToAddr(arg->argv[arg->argn + 1], &localIP);
265 if (error) {
266 prompt_Printf(arg->prompt, "proto redirect: invalid src address\n");
267 return 1;
268 }
269
270 if (arg->argc >= arg->argn + 3) {
271 error = StrToAddr(arg->argv[arg->argn + 2], &publicIP);
272 if (error) {
273 prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n");
274 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
275 arg->cmd->syntax);
276 return 1;
277 }
278 } else
279 publicIP.s_addr = INADDR_ANY;
280
281 if (arg->argc == arg->argn + 4) {
282 error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP);
283 if (error) {
284 prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n");
285 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
286 arg->cmd->syntax);
287 return 1;
288 }
289 } else
290 remoteIP.s_addr = INADDR_ANY;
291
292 link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto);
293 if (link == NULL) {
294 prompt_Printf(arg->prompt, "proto redirect: packet aliasing"
295 " engine error\n");
296 prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name,
297 arg->cmd->syntax);
298 }
299 } else
300 return -1;
301
302 return 0;
303 }
304
305
306 static int
StrToAddr(const char * str,struct in_addr * addr)307 StrToAddr(const char *str, struct in_addr *addr)
308 {
309 struct hostent *hp;
310
311 if (inet_aton(str, addr))
312 return 0;
313
314 hp = gethostbyname(str);
315 if (!hp) {
316 log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str);
317 return -1;
318 }
319 *addr = *((struct in_addr *) hp->h_addr);
320 return 0;
321 }
322
323
324 static int
StrToPort(const char * str,u_short * port,const char * proto)325 StrToPort(const char *str, u_short *port, const char *proto)
326 {
327 struct servent *sp;
328 char *end;
329
330 *port = strtol(str, &end, 10);
331 if (*end != '\0') {
332 sp = getservbyname(str, proto);
333 if (sp == NULL) {
334 log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n",
335 str, proto);
336 return -1;
337 }
338 *port = ntohs(sp->s_port);
339 }
340
341 return 0;
342 }
343
344 static int
StrToPortRange(const char * str,u_short * low,u_short * high,const char * proto)345 StrToPortRange(const char *str, u_short *low, u_short *high, const char *proto)
346 {
347 char *minus;
348 int res;
349
350 minus = strchr(str, '-');
351 if (minus)
352 *minus = '\0'; /* Cheat the const-ness ! */
353
354 res = StrToPort(str, low, proto);
355
356 if (minus)
357 *minus = '-'; /* Cheat the const-ness ! */
358
359 if (res == 0) {
360 if (minus)
361 res = StrToPort(minus + 1, high, proto);
362 else
363 *high = *low;
364 }
365
366 return res;
367 }
368
369 static int
StrToAddrAndPort(const char * str,struct in_addr * addr,u_short * low,u_short * high,const char * proto)370 StrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low,
371 u_short *high, const char *proto)
372 {
373 char *colon;
374 int res;
375
376 colon = strchr(str, ':');
377 if (!colon) {
378 log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str);
379 return -1;
380 }
381
382 *colon = '\0'; /* Cheat the const-ness ! */
383 res = StrToAddr(str, addr);
384 *colon = ':'; /* Cheat the const-ness ! */
385 if (res != 0)
386 return -1;
387
388 return StrToPortRange(colon + 1, low, high, proto);
389 }
390
391 int
nat_ProxyRule(struct cmdargs const * arg)392 nat_ProxyRule(struct cmdargs const *arg)
393 {
394 char cmd[LINE_LEN];
395 int f, pos;
396 size_t len;
397
398 if (arg->argn >= arg->argc)
399 return -1;
400
401 for (f = arg->argn, pos = 0; f < arg->argc; f++) {
402 len = strlen(arg->argv[f]);
403 if (sizeof cmd - pos < len + (len ? 1 : 0))
404 break;
405 if (len)
406 cmd[pos++] = ' ';
407 strcpy(cmd + pos, arg->argv[f]);
408 pos += len;
409 }
410
411 return LibAliasProxyRule(la, cmd);
412 }
413
414 int
nat_SetTarget(struct cmdargs const * arg)415 nat_SetTarget(struct cmdargs const *arg)
416 {
417 struct in_addr addr;
418
419 if (arg->argc == arg->argn) {
420 addr.s_addr = INADDR_ANY;
421 LibAliasSetTarget(la, addr);
422 return 0;
423 }
424
425 if (arg->argc != arg->argn + 1)
426 return -1;
427
428 if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) {
429 addr.s_addr = INADDR_ANY;
430 LibAliasSetTarget(la, addr);
431 return 0;
432 }
433
434 addr = GetIpAddr(arg->argv[arg->argn]);
435 if (addr.s_addr == INADDR_NONE) {
436 log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]);
437 return 1;
438 }
439
440 LibAliasSetTarget(la, addr);
441 return 0;
442 }
443
444 #ifndef NO_FW_PUNCH
445 int
nat_PunchFW(struct cmdargs const * arg)446 nat_PunchFW(struct cmdargs const *arg)
447 {
448 char *end;
449 long base, count;
450
451 if (arg->argc == arg->argn) {
452 LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW);
453 return 0;
454 }
455
456 if (arg->argc != arg->argn + 2)
457 return -1;
458
459 base = strtol(arg->argv[arg->argn], &end, 10);
460 if (*end != '\0' || base < 0)
461 return -1;
462
463 count = strtol(arg->argv[arg->argn + 1], &end, 10);
464 if (*end != '\0' || count < 0)
465 return -1;
466
467 LibAliasSetFWBase(la, base, count);
468 LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW);
469
470 return 0;
471 }
472 #endif
473
474 int
nat_SkinnyPort(struct cmdargs const * arg)475 nat_SkinnyPort(struct cmdargs const *arg)
476 {
477 char *end;
478 long port;
479
480 if (arg->argc == arg->argn) {
481 LibAliasSetSkinnyPort(la, 0);
482 return 0;
483 }
484
485 if (arg->argc != arg->argn + 1)
486 return -1;
487
488 port = strtol(arg->argv[arg->argn], &end, 10);
489 if (*end != '\0' || port < 0)
490 return -1;
491
492 LibAliasSetSkinnyPort(la, port);
493
494 return 0;
495 }
496
497 static struct mbuf *
nat_LayerPush(struct bundle * bundle,struct link * l __unused,struct mbuf * bp,int pri __unused,u_short * proto)498 nat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp,
499 int pri __unused, u_short *proto)
500 {
501 if (!bundle->NatEnabled || *proto != PROTO_IP)
502 return bp;
503
504 log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n");
505 m_settype(bp, MB_NATOUT);
506 /* Ensure there's a bit of extra buffer for the NAT code... */
507 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF));
508 LibAliasOut(la, MBUF_CTOP(bp), bp->m_len);
509 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
510
511 return bp;
512 }
513
514 static struct mbuf *
nat_LayerPull(struct bundle * bundle,struct link * l __unused,struct mbuf * bp,u_short * proto)515 nat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp,
516 u_short *proto)
517 {
518 static int gfrags;
519 int ret, len, nfrags;
520 struct mbuf **last;
521 char *fptr;
522
523 if (!bundle->NatEnabled || *proto != PROTO_IP)
524 return bp;
525
526 log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n");
527 m_settype(bp, MB_NATIN);
528 /* Ensure there's a bit of extra buffer for the NAT code... */
529 bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF));
530 ret = LibAliasIn(la, MBUF_CTOP(bp), bp->m_len);
531
532 bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len);
533 if (bp->m_len > MAX_MRU) {
534 log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n",
535 (unsigned long)bp->m_len);
536 m_freem(bp);
537 return NULL;
538 }
539
540 switch (ret) {
541 case PKT_ALIAS_OK:
542 break;
543
544 case PKT_ALIAS_UNRESOLVED_FRAGMENT:
545 /* Save the data for later */
546 if ((fptr = malloc(bp->m_len)) == NULL) {
547 log_Printf(LogWARN, "nat_LayerPull: Dropped unresolved fragment -"
548 " out of memory!\n");
549 m_freem(bp);
550 bp = NULL;
551 } else {
552 bp = mbuf_Read(bp, fptr, bp->m_len);
553 LibAliasSaveFragment(la, fptr);
554 log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n",
555 (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags);
556 }
557 break;
558
559 case PKT_ALIAS_FOUND_HEADER_FRAGMENT:
560 /* Fetch all the saved fragments and chain them on the end of `bp' */
561 last = &bp->m_nextpkt;
562 nfrags = 0;
563 while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) {
564 nfrags++;
565 LibAliasFragmentIn(la, MBUF_CTOP(bp), fptr);
566 len = ntohs(((struct ip *)fptr)->ip_len);
567 *last = m_get(len, MB_NATIN);
568 memcpy(MBUF_CTOP(*last), fptr, len);
569 free(fptr);
570 last = &(*last)->m_nextpkt;
571 }
572 gfrags -= nfrags;
573 log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no"
574 "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id,
575 nfrags, gfrags);
576 break;
577
578 case PKT_ALIAS_IGNORED:
579 if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) {
580 log_Printf(LogTCPIP, "NAT engine denied data:\n");
581 m_freem(bp);
582 bp = NULL;
583 } else if (log_IsKept(LogTCPIP)) {
584 log_Printf(LogTCPIP, "NAT engine ignored data:\n");
585 PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL,
586 NULL, NULL);
587 }
588 break;
589
590 default:
591 log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret);
592 m_freem(bp);
593 bp = NULL;
594 break;
595 }
596
597 return bp;
598 }
599
600 struct layer natlayer =
601 { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull };
602