131921Sbrian/*- 285965Sbrian * Copyright (c) 2001 Charles Mott <cm@linktel.net> 377690Sbrian * Brian Somers <brian@Awfulhak.org> 477690Sbrian * All rights reserved. 531921Sbrian * 677690Sbrian * Redistribution and use in source and binary forms, with or without 777690Sbrian * modification, are permitted provided that the following conditions 877690Sbrian * are met: 977690Sbrian * 1. Redistributions of source code must retain the above copyright 1077690Sbrian * notice, this list of conditions and the following disclaimer. 1177690Sbrian * 2. Redistributions in binary form must reproduce the above copyright 1277690Sbrian * notice, this list of conditions and the following disclaimer in the 1377690Sbrian * documentation and/or other materials provided with the distribution. 1477690Sbrian * 1577690Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1677690Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1777690Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1877690Sbrian * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1977690Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2077690Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2177690Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2277690Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2377690Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2477690Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2577690Sbrian * SUCH DAMAGE. 2677690Sbrian * 2750479Speter * $FreeBSD: releng/11.0/usr.sbin/ppp/nat_cmd.c 223492 2011-06-24 07:05:20Z kevlo $ 2830715Sbrian */ 2926034Sbrian 3043313Sbrian#include <sys/param.h> 3126034Sbrian#include <netinet/in.h> 3226034Sbrian#include <arpa/inet.h> 3330715Sbrian#include <netdb.h> 3437191Sbrian#include <netinet/in_systm.h> 3537191Sbrian#include <netinet/ip.h> 3681634Sbrian#include <sys/socket.h> 3737191Sbrian#include <sys/un.h> 3826034Sbrian 39102500Sbrian#include <stdarg.h> 4030715Sbrian#include <stdio.h> 4130715Sbrian#include <stdlib.h> 4230715Sbrian#include <string.h> 4336285Sbrian#include <termios.h> 4430715Sbrian 4558037Sbrian#ifdef LOCALNAT 4658037Sbrian#include "alias.h" 4758037Sbrian#else 4846086Sbrian#include <alias.h> 4939395Sbrian#endif 5058037Sbrian 5146686Sbrian#include "layer.h" 5246686Sbrian#include "proto.h" 5337009Sbrian#include "defs.h" 5431343Sbrian#include "command.h" 5530715Sbrian#include "log.h" 5651075Sbrian#include "nat_cmd.h" 5736285Sbrian#include "descriptor.h" 5836285Sbrian#include "prompt.h" 5937191Sbrian#include "timer.h" 6037191Sbrian#include "fsm.h" 6137191Sbrian#include "slcompress.h" 6237191Sbrian#include "throughput.h" 6337191Sbrian#include "iplist.h" 6438557Sbrian#include "mbuf.h" 6537191Sbrian#include "lqr.h" 6637191Sbrian#include "hdlc.h" 6781634Sbrian#include "ncpaddr.h" 6881634Sbrian#include "ip.h" 6938557Sbrian#include "ipcp.h" 7081634Sbrian#include "ipv6cp.h" 7137191Sbrian#include "lcp.h" 7237191Sbrian#include "ccp.h" 7337191Sbrian#include "link.h" 7437191Sbrian#include "mp.h" 7537191Sbrian#include "filter.h" 7643313Sbrian#ifndef NORADIUS 7743313Sbrian#include "radius.h" 7843313Sbrian#endif 7981634Sbrian#include "ncp.h" 8037191Sbrian#include "bundle.h" 8126034Sbrian 8226034Sbrian 8355353Sbrian#define NAT_EXTRABUF (13) 8455353Sbrian 8531343Sbrianstatic int StrToAddr(const char *, struct in_addr *); 8645042Sbrianstatic int StrToPortRange(const char *, u_short *, u_short *, const char *); 8745042Sbrianstatic int StrToAddrAndPort(const char *, struct in_addr *, u_short *, 8845042Sbrian u_short *, const char *); 8926034Sbrian 90177100Spisoextern struct libalias *la; 91177100Spiso 9247860Sbrianstatic void 9347860Sbrianlowhigh(u_short *a, u_short *b) 9447860Sbrian{ 9547860Sbrian if (a > b) { 9647860Sbrian u_short c; 9726034Sbrian 9847860Sbrian c = *b; 9947860Sbrian *b = *a; 10047860Sbrian *a = c; 10147860Sbrian } 10247860Sbrian} 10347860Sbrian 10426034Sbrianint 10550059Sbriannat_RedirectPort(struct cmdargs const *arg) 10626034Sbrian{ 10750059Sbrian if (!arg->bundle->NatEnabled) { 10836285Sbrian prompt_Printf(arg->prompt, "Alias not enabled\n"); 10931756Sbrian return 1; 11047860Sbrian } else if (arg->argc == arg->argn + 3 || arg->argc == arg->argn + 4) { 11128679Sbrian char proto_constant; 11231343Sbrian const char *proto; 11347860Sbrian struct in_addr localaddr; 11447860Sbrian u_short hlocalport, llocalport; 11547860Sbrian struct in_addr aliasaddr; 11647860Sbrian u_short haliasport, laliasport; 11747860Sbrian struct in_addr remoteaddr; 11847860Sbrian u_short hremoteport, lremoteport; 11947860Sbrian struct alias_link *link; 12028679Sbrian int error; 12126034Sbrian 12236285Sbrian proto = arg->argv[arg->argn]; 12328679Sbrian if (strcmp(proto, "tcp") == 0) { 12428679Sbrian proto_constant = IPPROTO_TCP; 12528679Sbrian } else if (strcmp(proto, "udp") == 0) { 12628679Sbrian proto_constant = IPPROTO_UDP; 12728679Sbrian } else { 12836285Sbrian prompt_Printf(arg->prompt, "port redirect: protocol must be" 12936285Sbrian " tcp or udp\n"); 13045042Sbrian return -1; 13128679Sbrian } 13226034Sbrian 13347860Sbrian error = StrToAddrAndPort(arg->argv[arg->argn+1], &localaddr, &llocalport, 13445042Sbrian &hlocalport, proto); 13528679Sbrian if (error) { 13650059Sbrian prompt_Printf(arg->prompt, "nat port: error reading localaddr:port\n"); 13745042Sbrian return -1; 13828679Sbrian } 13947860Sbrian 14045042Sbrian error = StrToPortRange(arg->argv[arg->argn+2], &laliasport, &haliasport, 14145042Sbrian proto); 14228679Sbrian if (error) { 14350059Sbrian prompt_Printf(arg->prompt, "nat port: error reading alias port\n"); 14445042Sbrian return -1; 14528679Sbrian } 14647860Sbrian aliasaddr.s_addr = INADDR_ANY; 14726034Sbrian 14847860Sbrian if (arg->argc == arg->argn + 4) { 14947860Sbrian error = StrToAddrAndPort(arg->argv[arg->argn+3], &remoteaddr, 15047860Sbrian &lremoteport, &hremoteport, proto); 15147860Sbrian if (error) { 15250059Sbrian prompt_Printf(arg->prompt, "nat port: error reading " 15347860Sbrian "remoteaddr:port\n"); 15447860Sbrian return -1; 15547860Sbrian } 15647860Sbrian } else { 15747860Sbrian remoteaddr.s_addr = INADDR_ANY; 15847860Sbrian lremoteport = hremoteport = 0; 15945042Sbrian } 16026034Sbrian 16147860Sbrian lowhigh(&llocalport, &hlocalport); 16247860Sbrian lowhigh(&laliasport, &haliasport); 16347860Sbrian lowhigh(&lremoteport, &hremoteport); 16445042Sbrian 16545042Sbrian if (haliasport - laliasport != hlocalport - llocalport) { 16650059Sbrian prompt_Printf(arg->prompt, "nat port: local & alias port ranges " 16747860Sbrian "are not equal\n"); 16845042Sbrian return -1; 16945042Sbrian } 17045042Sbrian 17147860Sbrian if (hremoteport && hremoteport - lremoteport != hlocalport - llocalport) { 17250059Sbrian prompt_Printf(arg->prompt, "nat port: local & remote port ranges " 17347860Sbrian "are not equal\n"); 17447860Sbrian return -1; 17547860Sbrian } 17647860Sbrian 177195772Sbrian do { 178177100Spiso link = LibAliasRedirectPort(la, localaddr, htons(llocalport), 17947860Sbrian remoteaddr, htons(lremoteport), 18047860Sbrian aliasaddr, htons(laliasport), 18145042Sbrian proto_constant); 18245042Sbrian 18345042Sbrian if (link == NULL) { 18450059Sbrian prompt_Printf(arg->prompt, "nat port: %d: error %d\n", laliasport, 18547860Sbrian error); 18645042Sbrian return 1; 18745042Sbrian } 18847860Sbrian llocalport++; 18947860Sbrian if (hremoteport) 19047860Sbrian lremoteport++; 191195772Sbrian } while (laliasport++ < haliasport); 19226034Sbrian 19347860Sbrian return 0; 19447860Sbrian } 19547860Sbrian 19647860Sbrian return -1; 19726034Sbrian} 19826034Sbrian 19926034Sbrian 20026034Sbrianint 20150059Sbriannat_RedirectAddr(struct cmdargs const *arg) 20226034Sbrian{ 20350059Sbrian if (!arg->bundle->NatEnabled) { 20450059Sbrian prompt_Printf(arg->prompt, "nat not enabled\n"); 20531756Sbrian return 1; 20636285Sbrian } else if (arg->argc == arg->argn+2) { 20728679Sbrian int error; 20847860Sbrian struct in_addr localaddr, aliasaddr; 20928679Sbrian struct alias_link *link; 21028679Sbrian 21147860Sbrian error = StrToAddr(arg->argv[arg->argn], &localaddr); 21228679Sbrian if (error) { 21336285Sbrian prompt_Printf(arg->prompt, "address redirect: invalid local address\n"); 21428679Sbrian return 1; 21528679Sbrian } 21647860Sbrian error = StrToAddr(arg->argv[arg->argn+1], &aliasaddr); 21728679Sbrian if (error) { 21836285Sbrian prompt_Printf(arg->prompt, "address redirect: invalid alias address\n"); 21995258Sdes prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 22036285Sbrian arg->cmd->syntax); 22128679Sbrian return 1; 22228679Sbrian } 223177100Spiso link = LibAliasRedirectAddr(la, localaddr, aliasaddr); 22436285Sbrian if (link == NULL) { 22536285Sbrian prompt_Printf(arg->prompt, "address redirect: packet aliasing" 22636285Sbrian " engine error\n"); 22795258Sdes prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 22836285Sbrian arg->cmd->syntax); 22928679Sbrian } 23031756Sbrian } else 23131756Sbrian return -1; 23226034Sbrian 23331756Sbrian return 0; 23426034Sbrian} 23526034Sbrian 23626034Sbrian 23779433Sbrianint 23879433Sbriannat_RedirectProto(struct cmdargs const *arg) 23979433Sbrian{ 24079433Sbrian if (!arg->bundle->NatEnabled) { 24179433Sbrian prompt_Printf(arg->prompt, "nat not enabled\n"); 24279433Sbrian return 1; 24379433Sbrian } else if (arg->argc >= arg->argn + 2 && arg->argc <= arg->argn + 4) { 24479433Sbrian struct in_addr localIP, publicIP, remoteIP; 24579433Sbrian struct alias_link *link; 24679433Sbrian struct protoent *pe; 247134789Sbrian int error; 248134789Sbrian unsigned len; 24979433Sbrian 25079433Sbrian len = strlen(arg->argv[arg->argn]); 25179433Sbrian if (len == 0) { 25279433Sbrian prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 25379433Sbrian return 1; 25479433Sbrian } 25579433Sbrian if (strspn(arg->argv[arg->argn], "01234567") == len) 25679433Sbrian pe = getprotobynumber(atoi(arg->argv[arg->argn])); 25779433Sbrian else 25879433Sbrian pe = getprotobyname(arg->argv[arg->argn]); 25979433Sbrian if (pe == NULL) { 26079433Sbrian prompt_Printf(arg->prompt, "proto redirect: invalid protocol\n"); 26179433Sbrian return 1; 26279433Sbrian } 26379433Sbrian 26479433Sbrian error = StrToAddr(arg->argv[arg->argn + 1], &localIP); 26579433Sbrian if (error) { 26679433Sbrian prompt_Printf(arg->prompt, "proto redirect: invalid src address\n"); 26779433Sbrian return 1; 26879433Sbrian } 26979433Sbrian 27079433Sbrian if (arg->argc >= arg->argn + 3) { 27179433Sbrian error = StrToAddr(arg->argv[arg->argn + 2], &publicIP); 27279433Sbrian if (error) { 27379433Sbrian prompt_Printf(arg->prompt, "proto redirect: invalid alias address\n"); 27495258Sdes prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 27579433Sbrian arg->cmd->syntax); 27679433Sbrian return 1; 27779433Sbrian } 27879433Sbrian } else 27979433Sbrian publicIP.s_addr = INADDR_ANY; 28079433Sbrian 28179433Sbrian if (arg->argc == arg->argn + 4) { 28279433Sbrian error = StrToAddr(arg->argv[arg->argn + 2], &remoteIP); 28379433Sbrian if (error) { 28479433Sbrian prompt_Printf(arg->prompt, "proto redirect: invalid dst address\n"); 28595258Sdes prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 28679433Sbrian arg->cmd->syntax); 28779433Sbrian return 1; 28879433Sbrian } 28979433Sbrian } else 29079433Sbrian remoteIP.s_addr = INADDR_ANY; 29179433Sbrian 292177100Spiso link = LibAliasRedirectProto(la, localIP, remoteIP, publicIP, pe->p_proto); 29379433Sbrian if (link == NULL) { 29479433Sbrian prompt_Printf(arg->prompt, "proto redirect: packet aliasing" 29579433Sbrian " engine error\n"); 29695258Sdes prompt_Printf(arg->prompt, "usage: nat %s %s\n", arg->cmd->name, 29779433Sbrian arg->cmd->syntax); 29879433Sbrian } 29979433Sbrian } else 30079433Sbrian return -1; 30179433Sbrian 30279433Sbrian return 0; 30379433Sbrian} 30479433Sbrian 30579433Sbrian 30626034Sbrianstatic int 30731343SbrianStrToAddr(const char *str, struct in_addr *addr) 30826034Sbrian{ 30928679Sbrian struct hostent *hp; 31026034Sbrian 31128679Sbrian if (inet_aton(str, addr)) 31228679Sbrian return 0; 31326034Sbrian 31428679Sbrian hp = gethostbyname(str); 31528679Sbrian if (!hp) { 31636285Sbrian log_Printf(LogWARN, "StrToAddr: Unknown host %s.\n", str); 31728679Sbrian return -1; 31828679Sbrian } 31928679Sbrian *addr = *((struct in_addr *) hp->h_addr); 32028679Sbrian return 0; 32126034Sbrian} 32226034Sbrian 32326034Sbrian 32426034Sbrianstatic int 32531343SbrianStrToPort(const char *str, u_short *port, const char *proto) 32626034Sbrian{ 32728679Sbrian struct servent *sp; 32828679Sbrian char *end; 32926034Sbrian 33045042Sbrian *port = strtol(str, &end, 10); 33145042Sbrian if (*end != '\0') { 33245042Sbrian sp = getservbyname(str, proto); 33345042Sbrian if (sp == NULL) { 33445042Sbrian log_Printf(LogWARN, "StrToAddr: Unknown port or service %s/%s.\n", 33545042Sbrian str, proto); 33645042Sbrian return -1; 33745042Sbrian } 33845042Sbrian *port = ntohs(sp->s_port); 33928679Sbrian } 34045042Sbrian 34128679Sbrian return 0; 34226034Sbrian} 34326034Sbrian 34445042Sbrianstatic int 34545042SbrianStrToPortRange(const char *str, u_short *low, u_short *high, const char *proto) 34645042Sbrian{ 34745042Sbrian char *minus; 34845042Sbrian int res; 34926034Sbrian 35045042Sbrian minus = strchr(str, '-'); 35145042Sbrian if (minus) 35245042Sbrian *minus = '\0'; /* Cheat the const-ness ! */ 35345042Sbrian 35445042Sbrian res = StrToPort(str, low, proto); 35545042Sbrian 35645042Sbrian if (minus) 35745042Sbrian *minus = '-'; /* Cheat the const-ness ! */ 35845042Sbrian 35945042Sbrian if (res == 0) { 36045042Sbrian if (minus) 36145042Sbrian res = StrToPort(minus + 1, high, proto); 36245042Sbrian else 36345042Sbrian *high = *low; 36445042Sbrian } 36545042Sbrian 36645042Sbrian return res; 36745042Sbrian} 36845042Sbrian 36931343Sbrianstatic int 37045042SbrianStrToAddrAndPort(const char *str, struct in_addr *addr, u_short *low, 37145042Sbrian u_short *high, const char *proto) 37226034Sbrian{ 37331343Sbrian char *colon; 37431343Sbrian int res; 37526034Sbrian 37631343Sbrian colon = strchr(str, ':'); 37731343Sbrian if (!colon) { 37836285Sbrian log_Printf(LogWARN, "StrToAddrAndPort: %s is missing port number.\n", str); 37928679Sbrian return -1; 38028679Sbrian } 38126034Sbrian 38231343Sbrian *colon = '\0'; /* Cheat the const-ness ! */ 38331343Sbrian res = StrToAddr(str, addr); 38431343Sbrian *colon = ':'; /* Cheat the const-ness ! */ 38531343Sbrian if (res != 0) 38628679Sbrian return -1; 38726034Sbrian 38845042Sbrian return StrToPortRange(colon + 1, low, high, proto); 38926034Sbrian} 39044547Sbrian 39144547Sbrianint 39250059Sbriannat_ProxyRule(struct cmdargs const *arg) 39344547Sbrian{ 39444547Sbrian char cmd[LINE_LEN]; 39544547Sbrian int f, pos; 39644547Sbrian size_t len; 39744547Sbrian 39844547Sbrian if (arg->argn >= arg->argc) 39944547Sbrian return -1; 40044547Sbrian 40144547Sbrian for (f = arg->argn, pos = 0; f < arg->argc; f++) { 40244547Sbrian len = strlen(arg->argv[f]); 40372322Sbrian if (sizeof cmd - pos < len + (len ? 1 : 0)) 40444547Sbrian break; 40572322Sbrian if (len) 40644547Sbrian cmd[pos++] = ' '; 40744547Sbrian strcpy(cmd + pos, arg->argv[f]); 40844547Sbrian pos += len; 40944547Sbrian } 41044547Sbrian 411177100Spiso return LibAliasProxyRule(la, cmd); 41244547Sbrian} 41344557Sbrian 41444557Sbrianint 41558867Sbriannat_SetTarget(struct cmdargs const *arg) 41658867Sbrian{ 41758867Sbrian struct in_addr addr; 41858867Sbrian 41958867Sbrian if (arg->argc == arg->argn) { 42060365Sbrian addr.s_addr = INADDR_ANY; 421177100Spiso LibAliasSetTarget(la, addr); 42258867Sbrian return 0; 42358867Sbrian } 42458867Sbrian 42558867Sbrian if (arg->argc != arg->argn + 1) 42658867Sbrian return -1; 42758867Sbrian 42860367Sbrian if (!strcasecmp(arg->argv[arg->argn], "MYADDR")) { 42960365Sbrian addr.s_addr = INADDR_ANY; 430177100Spiso LibAliasSetTarget(la, addr); 43160365Sbrian return 0; 43260365Sbrian } 43360365Sbrian 43458867Sbrian addr = GetIpAddr(arg->argv[arg->argn]); 43558867Sbrian if (addr.s_addr == INADDR_NONE) { 43658867Sbrian log_Printf(LogWARN, "%s: invalid address\n", arg->argv[arg->argn]); 43758867Sbrian return 1; 43858867Sbrian } 43958867Sbrian 440177100Spiso LibAliasSetTarget(la, addr); 44158867Sbrian return 0; 44258867Sbrian} 44358867Sbrian 44481033Sbrian#ifndef NO_FW_PUNCH 44581033Sbrianint 44681033Sbriannat_PunchFW(struct cmdargs const *arg) 44781033Sbrian{ 44881033Sbrian char *end; 44981033Sbrian long base, count; 45081033Sbrian 45181033Sbrian if (arg->argc == arg->argn) { 452177100Spiso LibAliasSetMode(la, 0, PKT_ALIAS_PUNCH_FW); 45381033Sbrian return 0; 45481033Sbrian } 45581033Sbrian 45681033Sbrian if (arg->argc != arg->argn + 2) 45781033Sbrian return -1; 45881033Sbrian 45981033Sbrian base = strtol(arg->argv[arg->argn], &end, 10); 46081033Sbrian if (*end != '\0' || base < 0) 46181033Sbrian return -1; 46281033Sbrian 46381033Sbrian count = strtol(arg->argv[arg->argn + 1], &end, 10); 46481033Sbrian if (*end != '\0' || count < 0) 46581033Sbrian return -1; 46681033Sbrian 467177100Spiso LibAliasSetFWBase(la, base, count); 468177100Spiso LibAliasSetMode(la, PKT_ALIAS_PUNCH_FW, PKT_ALIAS_PUNCH_FW); 46981033Sbrian 47081033Sbrian return 0; 47181033Sbrian} 47281033Sbrian#endif 47381033Sbrian 474120372Smarcusint 475120372Smarcusnat_SkinnyPort(struct cmdargs const *arg) 476120372Smarcus{ 477120372Smarcus char *end; 478120372Smarcus long port; 479120372Smarcus 480120372Smarcus if (arg->argc == arg->argn) { 481177100Spiso LibAliasSetSkinnyPort(la, 0); 482120372Smarcus return 0; 483120372Smarcus } 484120372Smarcus 485120372Smarcus if (arg->argc != arg->argn + 1) 486120372Smarcus return -1; 487120372Smarcus 488120372Smarcus port = strtol(arg->argv[arg->argn], &end, 10); 489120372Smarcus if (*end != '\0' || port < 0) 490120372Smarcus return -1; 491120372Smarcus 492177100Spiso LibAliasSetSkinnyPort(la, port); 493120372Smarcus 494120372Smarcus return 0; 495120372Smarcus} 496120372Smarcus 49746686Sbrianstatic struct mbuf * 498134789Sbriannat_LayerPush(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, 499134789Sbrian int pri __unused, u_short *proto) 50046686Sbrian{ 50150059Sbrian if (!bundle->NatEnabled || *proto != PROTO_IP) 50246686Sbrian return bp; 50347061Sbrian 50450059Sbrian log_Printf(LogDEBUG, "nat_LayerPush: PROTO_IP -> PROTO_IP\n"); 50554912Sbrian m_settype(bp, MB_NATOUT); 50655353Sbrian /* Ensure there's a bit of extra buffer for the NAT code... */ 50755353Sbrian bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 508177100Spiso LibAliasOut(la, MBUF_CTOP(bp), bp->m_len); 50955353Sbrian bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 51046686Sbrian 51146686Sbrian return bp; 51246686Sbrian} 51346686Sbrian 51446686Sbrianstatic struct mbuf * 515134789Sbriannat_LayerPull(struct bundle *bundle, struct link *l __unused, struct mbuf *bp, 51646686Sbrian u_short *proto) 51746686Sbrian{ 51858285Sbrian static int gfrags; 51958285Sbrian int ret, len, nfrags; 52046686Sbrian struct mbuf **last; 52146686Sbrian char *fptr; 52246686Sbrian 52350059Sbrian if (!bundle->NatEnabled || *proto != PROTO_IP) 52446686Sbrian return bp; 52546686Sbrian 52650059Sbrian log_Printf(LogDEBUG, "nat_LayerPull: PROTO_IP -> PROTO_IP\n"); 52754912Sbrian m_settype(bp, MB_NATIN); 52855353Sbrian /* Ensure there's a bit of extra buffer for the NAT code... */ 52955353Sbrian bp = m_pullup(m_append(bp, NULL, NAT_EXTRABUF)); 530177100Spiso ret = LibAliasIn(la, MBUF_CTOP(bp), bp->m_len); 53146686Sbrian 53260827Sbrian bp->m_len = ntohs(((struct ip *)MBUF_CTOP(bp))->ip_len); 53354912Sbrian if (bp->m_len > MAX_MRU) { 53458042Sbrian log_Printf(LogWARN, "nat_LayerPull: Problem with IP header length (%lu)\n", 53558042Sbrian (unsigned long)bp->m_len); 53654912Sbrian m_freem(bp); 53746686Sbrian return NULL; 53846686Sbrian } 53946686Sbrian 54046686Sbrian switch (ret) { 54146686Sbrian case PKT_ALIAS_OK: 54246686Sbrian break; 54346686Sbrian 54446686Sbrian case PKT_ALIAS_UNRESOLVED_FRAGMENT: 54546686Sbrian /* Save the data for later */ 546136375Sbrian if ((fptr = malloc(bp->m_len)) == NULL) { 547136375Sbrian log_Printf(LogWARN, "nat_LayerPull: Dropped unresolved fragment -" 548136375Sbrian " out of memory!\n"); 549136375Sbrian m_freem(bp); 550136375Sbrian bp = NULL; 551136375Sbrian } else { 552136375Sbrian bp = mbuf_Read(bp, fptr, bp->m_len); 553177100Spiso LibAliasSaveFragment(la, fptr); 554136375Sbrian log_Printf(LogDEBUG, "Store another frag (%lu) - now %d\n", 555136375Sbrian (unsigned long)((struct ip *)fptr)->ip_id, ++gfrags); 556136375Sbrian } 55746686Sbrian break; 55846686Sbrian 55946686Sbrian case PKT_ALIAS_FOUND_HEADER_FRAGMENT: 56046686Sbrian /* Fetch all the saved fragments and chain them on the end of `bp' */ 56154912Sbrian last = &bp->m_nextpkt; 56258285Sbrian nfrags = 0; 563177100Spiso while ((fptr = LibAliasGetFragment(la, MBUF_CTOP(bp))) != NULL) { 56458285Sbrian nfrags++; 565177100Spiso LibAliasFragmentIn(la, MBUF_CTOP(bp), fptr); 56649046Sbrian len = ntohs(((struct ip *)fptr)->ip_len); 56754912Sbrian *last = m_get(len, MB_NATIN); 56849046Sbrian memcpy(MBUF_CTOP(*last), fptr, len); 56946686Sbrian free(fptr); 57054912Sbrian last = &(*last)->m_nextpkt; 57146686Sbrian } 57258285Sbrian gfrags -= nfrags; 57358285Sbrian log_Printf(LogDEBUG, "Found a frag header (%lu) - plus %d more frags (no" 57458285Sbrian "w %d)\n", (unsigned long)((struct ip *)MBUF_CTOP(bp))->ip_id, 57558285Sbrian nfrags, gfrags); 57646686Sbrian break; 57746686Sbrian 57858776Sbrian case PKT_ALIAS_IGNORED: 579177100Spiso if (LibAliasSetMode(la, 0, 0) & PKT_ALIAS_DENY_INCOMING) { 58067987Sbrian log_Printf(LogTCPIP, "NAT engine denied data:\n"); 58167987Sbrian m_freem(bp); 58267987Sbrian bp = NULL; 58367987Sbrian } else if (log_IsKept(LogTCPIP)) { 58458776Sbrian log_Printf(LogTCPIP, "NAT engine ignored data:\n"); 58581634Sbrian PacketCheck(bundle, AF_INET, MBUF_CTOP(bp), bp->m_len, NULL, 58681634Sbrian NULL, NULL); 58758776Sbrian } 58858776Sbrian break; 58958776Sbrian 59046686Sbrian default: 59158759Sbrian log_Printf(LogWARN, "nat_LayerPull: Dropped a packet (%d)....\n", ret); 59254912Sbrian m_freem(bp); 59346686Sbrian bp = NULL; 59446686Sbrian break; 59546686Sbrian } 59646686Sbrian 59746686Sbrian return bp; 59846686Sbrian} 59946686Sbrian 60050059Sbrianstruct layer natlayer = 60150059Sbrian { LAYER_NAT, "nat", nat_LayerPush, nat_LayerPull }; 602