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