Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 2001 Charles Mott <cm (at) linktel.net>
      3  *                    Brian Somers <brian (at) 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
     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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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 *
    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