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