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