The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/netgraph/ng_nat.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright 2005, Gleb Smirnoff <glebius@FreeBSD.org>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  *
   28  * $FreeBSD: stable/12/sys/netgraph/ng_nat.c 359707 2020-04-07 17:49:36Z eugen $
   29  */
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/kernel.h>
   34 #include <sys/mbuf.h>
   35 #include <sys/malloc.h>
   36 #include <sys/ctype.h>
   37 #include <sys/errno.h>
   38 #include <sys/syslog.h>
   39 
   40 #include <netinet/in_systm.h>
   41 #include <netinet/in.h>
   42 #include <netinet/ip.h>
   43 #include <netinet/ip_var.h>
   44 #include <netinet/tcp.h>
   45 #include <machine/in_cksum.h>
   46 
   47 #include <net/dlt.h>
   48 #include <net/ethernet.h>
   49 
   50 #include <netinet/libalias/alias.h>
   51 #include <netinet/libalias/alias_local.h>
   52 
   53 #include <netgraph/ng_message.h>
   54 #include <netgraph/ng_parse.h>
   55 #include <netgraph/ng_nat.h>
   56 #include <netgraph/netgraph.h>
   57 
   58 static ng_constructor_t ng_nat_constructor;
   59 static ng_rcvmsg_t      ng_nat_rcvmsg;
   60 static ng_shutdown_t    ng_nat_shutdown;
   61 static ng_newhook_t     ng_nat_newhook;
   62 static ng_rcvdata_t     ng_nat_rcvdata;
   63 static ng_disconnect_t  ng_nat_disconnect;
   64 
   65 static unsigned int     ng_nat_translate_flags(unsigned int x);
   66 
   67 /* Parse type for struct ng_nat_mode. */
   68 static const struct ng_parse_struct_field ng_nat_mode_fields[]
   69         = NG_NAT_MODE_INFO;
   70 static const struct ng_parse_type ng_nat_mode_type = {
   71         &ng_parse_struct_type,
   72         &ng_nat_mode_fields
   73 };
   74 
   75 /* Parse type for 'description' field in structs. */
   76 static const struct ng_parse_fixedstring_info ng_nat_description_info
   77         = { NG_NAT_DESC_LENGTH };
   78 static const struct ng_parse_type ng_nat_description_type = {
   79         &ng_parse_fixedstring_type,
   80         &ng_nat_description_info
   81 };
   82 
   83 /* Parse type for struct ng_nat_redirect_port. */
   84 static const struct ng_parse_struct_field ng_nat_redirect_port_fields[]
   85         = NG_NAT_REDIRECT_PORT_TYPE_INFO(&ng_nat_description_type);
   86 static const struct ng_parse_type ng_nat_redirect_port_type = {
   87         &ng_parse_struct_type,
   88         &ng_nat_redirect_port_fields
   89 };
   90 
   91 /* Parse type for struct ng_nat_redirect_addr. */
   92 static const struct ng_parse_struct_field ng_nat_redirect_addr_fields[]
   93         = NG_NAT_REDIRECT_ADDR_TYPE_INFO(&ng_nat_description_type);
   94 static const struct ng_parse_type ng_nat_redirect_addr_type = {
   95         &ng_parse_struct_type,
   96         &ng_nat_redirect_addr_fields
   97 };
   98 
   99 /* Parse type for struct ng_nat_redirect_proto. */
  100 static const struct ng_parse_struct_field ng_nat_redirect_proto_fields[]
  101         = NG_NAT_REDIRECT_PROTO_TYPE_INFO(&ng_nat_description_type);
  102 static const struct ng_parse_type ng_nat_redirect_proto_type = {
  103         &ng_parse_struct_type,
  104         &ng_nat_redirect_proto_fields
  105 };
  106 
  107 /* Parse type for struct ng_nat_add_server. */
  108 static const struct ng_parse_struct_field ng_nat_add_server_fields[]
  109         = NG_NAT_ADD_SERVER_TYPE_INFO;
  110 static const struct ng_parse_type ng_nat_add_server_type = {
  111         &ng_parse_struct_type,
  112         &ng_nat_add_server_fields
  113 };
  114 
  115 /* Parse type for one struct ng_nat_listrdrs_entry. */
  116 static const struct ng_parse_struct_field ng_nat_listrdrs_entry_fields[]
  117         = NG_NAT_LISTRDRS_ENTRY_TYPE_INFO(&ng_nat_description_type);
  118 static const struct ng_parse_type ng_nat_listrdrs_entry_type = {
  119         &ng_parse_struct_type,
  120         &ng_nat_listrdrs_entry_fields
  121 };
  122 
  123 /* Parse type for 'redirects' array in struct ng_nat_list_redirects. */
  124 static int
  125 ng_nat_listrdrs_ary_getLength(const struct ng_parse_type *type,
  126         const u_char *start, const u_char *buf)
  127 {
  128         const struct ng_nat_list_redirects *lr;
  129 
  130         lr = (const struct ng_nat_list_redirects *)
  131             (buf - offsetof(struct ng_nat_list_redirects, redirects));
  132         return lr->total_count;
  133 }
  134 
  135 static const struct ng_parse_array_info ng_nat_listrdrs_ary_info = {
  136         &ng_nat_listrdrs_entry_type,
  137         &ng_nat_listrdrs_ary_getLength,
  138         NULL
  139 };
  140 static const struct ng_parse_type ng_nat_listrdrs_ary_type = {
  141         &ng_parse_array_type,
  142         &ng_nat_listrdrs_ary_info
  143 };
  144 
  145 /* Parse type for struct ng_nat_list_redirects. */
  146 static const struct ng_parse_struct_field ng_nat_list_redirects_fields[]
  147         = NG_NAT_LIST_REDIRECTS_TYPE_INFO(&ng_nat_listrdrs_ary_type);
  148 static const struct ng_parse_type ng_nat_list_redirects_type = {
  149         &ng_parse_struct_type,
  150         &ng_nat_list_redirects_fields
  151 };
  152 
  153 /* Parse type for struct ng_nat_libalias_info. */
  154 static const struct ng_parse_struct_field ng_nat_libalias_info_fields[]
  155         = NG_NAT_LIBALIAS_INFO;
  156 static const struct ng_parse_type ng_nat_libalias_info_type = {
  157         &ng_parse_struct_type,
  158         &ng_nat_libalias_info_fields
  159 };
  160 
  161 /* List of commands and how to convert arguments to/from ASCII. */
  162 static const struct ng_cmdlist ng_nat_cmdlist[] = {
  163         {
  164           NGM_NAT_COOKIE,
  165           NGM_NAT_SET_IPADDR,
  166           "setaliasaddr",
  167           &ng_parse_ipaddr_type,
  168           NULL
  169         },
  170         {
  171           NGM_NAT_COOKIE,
  172           NGM_NAT_SET_MODE,
  173           "setmode",
  174           &ng_nat_mode_type,
  175           NULL
  176         },
  177         {
  178           NGM_NAT_COOKIE,
  179           NGM_NAT_SET_TARGET,
  180           "settarget",
  181           &ng_parse_ipaddr_type,
  182           NULL
  183         },
  184         {
  185           NGM_NAT_COOKIE,
  186           NGM_NAT_REDIRECT_PORT,
  187           "redirectport",
  188           &ng_nat_redirect_port_type,
  189           &ng_parse_uint32_type
  190         },
  191         {
  192           NGM_NAT_COOKIE,
  193           NGM_NAT_REDIRECT_ADDR,
  194           "redirectaddr",
  195           &ng_nat_redirect_addr_type,
  196           &ng_parse_uint32_type
  197         },
  198         {
  199           NGM_NAT_COOKIE,
  200           NGM_NAT_REDIRECT_PROTO,
  201           "redirectproto",
  202           &ng_nat_redirect_proto_type,
  203           &ng_parse_uint32_type
  204         },
  205         {
  206           NGM_NAT_COOKIE,
  207           NGM_NAT_REDIRECT_DYNAMIC,
  208           "redirectdynamic",
  209           &ng_parse_uint32_type,
  210           NULL
  211         },
  212         {
  213           NGM_NAT_COOKIE,
  214           NGM_NAT_REDIRECT_DELETE,
  215           "redirectdelete",
  216           &ng_parse_uint32_type,
  217           NULL
  218         },
  219         {
  220           NGM_NAT_COOKIE,
  221           NGM_NAT_ADD_SERVER,
  222           "addserver",
  223           &ng_nat_add_server_type,
  224           NULL
  225         },
  226         {
  227           NGM_NAT_COOKIE,
  228           NGM_NAT_LIST_REDIRECTS,
  229           "listredirects",
  230           NULL,
  231           &ng_nat_list_redirects_type
  232         },
  233         {
  234           NGM_NAT_COOKIE,
  235           NGM_NAT_PROXY_RULE,
  236           "proxyrule",
  237           &ng_parse_string_type,
  238           NULL
  239         },
  240         {
  241           NGM_NAT_COOKIE,
  242           NGM_NAT_LIBALIAS_INFO,
  243           "libaliasinfo",
  244           NULL,
  245           &ng_nat_libalias_info_type
  246         },
  247         {
  248           NGM_NAT_COOKIE,
  249           NGM_NAT_SET_DLT,
  250           "setdlt",
  251           &ng_parse_uint8_type,
  252           NULL
  253         },
  254         {
  255           NGM_NAT_COOKIE,
  256           NGM_NAT_GET_DLT,
  257           "getdlt",
  258           NULL,
  259           &ng_parse_uint8_type
  260         },
  261         { 0 }
  262 };
  263 
  264 /* Netgraph node type descriptor. */
  265 static struct ng_type typestruct = {
  266         .version =      NG_ABI_VERSION,
  267         .name =         NG_NAT_NODE_TYPE,
  268         .constructor =  ng_nat_constructor,
  269         .rcvmsg =       ng_nat_rcvmsg,
  270         .shutdown =     ng_nat_shutdown,
  271         .newhook =      ng_nat_newhook,
  272         .rcvdata =      ng_nat_rcvdata,
  273         .disconnect =   ng_nat_disconnect,
  274         .cmdlist =      ng_nat_cmdlist,
  275 };
  276 NETGRAPH_INIT(nat, &typestruct);
  277 MODULE_DEPEND(ng_nat, libalias, 1, 1, 1);
  278 
  279 /* Element for list of redirects. */
  280 struct ng_nat_rdr_lst {
  281         STAILQ_ENTRY(ng_nat_rdr_lst) entries;
  282         struct alias_link       *lnk;
  283         struct ng_nat_listrdrs_entry rdr;
  284 };
  285 STAILQ_HEAD(rdrhead, ng_nat_rdr_lst);
  286 
  287 /* Information we store for each node. */
  288 struct ng_nat_priv {
  289         node_p          node;           /* back pointer to node */
  290         hook_p          in;             /* hook for demasquerading */
  291         hook_p          out;            /* hook for masquerading */
  292         struct libalias *lib;           /* libalias handler */
  293         uint32_t        flags;          /* status flags */
  294         uint32_t        rdrcount;       /* number or redirects in list */
  295         uint32_t        nextid;         /* for next in turn in list */
  296         struct rdrhead  redirhead;      /* redirect list header */
  297         uint8_t         dlt;            /* DLT_XXX from bpf.h */
  298 };
  299 typedef struct ng_nat_priv *priv_p;
  300 
  301 /* Values of flags */
  302 #define NGNAT_CONNECTED         0x1     /* We have both hooks connected */
  303 #define NGNAT_ADDR_DEFINED      0x2     /* NGM_NAT_SET_IPADDR happened */
  304 
  305 static int
  306 ng_nat_constructor(node_p node)
  307 {
  308         priv_p priv;
  309 
  310         /* Initialize private descriptor. */
  311         priv = malloc(sizeof(*priv), M_NETGRAPH, M_WAITOK | M_ZERO);
  312 
  313         /* Init aliasing engine. */
  314         priv->lib = LibAliasInit(NULL);
  315 
  316         /* Set same ports on. */
  317         (void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS,
  318             PKT_ALIAS_SAME_PORTS);
  319 
  320         /* Init redirects housekeeping. */
  321         priv->rdrcount = 0;
  322         priv->nextid = 1;
  323         priv->dlt = DLT_RAW;
  324         STAILQ_INIT(&priv->redirhead);
  325 
  326         /* Link structs together. */
  327         NG_NODE_SET_PRIVATE(node, priv);
  328         priv->node = node;
  329 
  330         /*
  331          * libalias is not thread safe, so our node
  332          * must be single threaded.
  333          */
  334         NG_NODE_FORCE_WRITER(node);
  335 
  336         return (0);
  337 }
  338 
  339 static int
  340 ng_nat_newhook(node_p node, hook_p hook, const char *name)
  341 {
  342         const priv_p priv = NG_NODE_PRIVATE(node);
  343 
  344         if (strcmp(name, NG_NAT_HOOK_IN) == 0) {
  345                 priv->in = hook;
  346         } else if (strcmp(name, NG_NAT_HOOK_OUT) == 0) {
  347                 priv->out = hook;
  348         } else
  349                 return (EINVAL);
  350 
  351         if (priv->out != NULL &&
  352             priv->in != NULL)
  353                 priv->flags |= NGNAT_CONNECTED;
  354 
  355         return(0);
  356 }
  357 
  358 static int
  359 ng_nat_rcvmsg(node_p node, item_p item, hook_p lasthook)
  360 {
  361         const priv_p priv = NG_NODE_PRIVATE(node);
  362         struct ng_mesg *resp = NULL;
  363         struct ng_mesg *msg;
  364         int error = 0;
  365 
  366         NGI_GET_MSG(item, msg);
  367 
  368         switch (msg->header.typecookie) {
  369         case NGM_NAT_COOKIE:
  370                 switch (msg->header.cmd) {
  371                 case NGM_NAT_SET_IPADDR:
  372                     {
  373                         struct in_addr *const ia = (struct in_addr *)msg->data;
  374 
  375                         if (msg->header.arglen < sizeof(*ia)) {
  376                                 error = EINVAL;
  377                                 break;
  378                         }
  379 
  380                         LibAliasSetAddress(priv->lib, *ia);
  381 
  382                         priv->flags |= NGNAT_ADDR_DEFINED;
  383                     }
  384                         break;
  385                 case NGM_NAT_SET_MODE:
  386                     {
  387                         struct ng_nat_mode *const mode = 
  388                             (struct ng_nat_mode *)msg->data;
  389 
  390                         if (msg->header.arglen < sizeof(*mode)) {
  391                                 error = EINVAL;
  392                                 break;
  393                         }
  394                         
  395                         if (LibAliasSetMode(priv->lib, 
  396                             ng_nat_translate_flags(mode->flags),
  397                             ng_nat_translate_flags(mode->mask)) < 0) {
  398                                 error = ENOMEM;
  399                                 break;
  400                         }
  401                     }
  402                         break;
  403                 case NGM_NAT_SET_TARGET:
  404                     {
  405                         struct in_addr *const ia = (struct in_addr *)msg->data;
  406 
  407                         if (msg->header.arglen < sizeof(*ia)) {
  408                                 error = EINVAL;
  409                                 break;
  410                         }
  411 
  412                         LibAliasSetTarget(priv->lib, *ia);
  413                     }
  414                         break;
  415                 case NGM_NAT_REDIRECT_PORT:
  416                     {
  417                         struct ng_nat_rdr_lst *entry;
  418                         struct ng_nat_redirect_port *const rp =
  419                             (struct ng_nat_redirect_port *)msg->data;
  420 
  421                         if (msg->header.arglen < sizeof(*rp)) {
  422                                 error = EINVAL;
  423                                 break;
  424                         }
  425 
  426                         if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
  427                             M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
  428                                 error = ENOMEM;
  429                                 break;
  430                         }
  431 
  432                         /* Try actual redirect. */
  433                         entry->lnk = LibAliasRedirectPort(priv->lib,
  434                                 rp->local_addr, htons(rp->local_port),
  435                                 rp->remote_addr, htons(rp->remote_port),
  436                                 rp->alias_addr, htons(rp->alias_port),
  437                                 rp->proto);
  438 
  439                         if (entry->lnk == NULL) {
  440                                 error = ENOMEM;
  441                                 free(entry, M_NETGRAPH);
  442                                 break;
  443                         }
  444 
  445                         /* Successful, save info in our internal list. */
  446                         entry->rdr.local_addr = rp->local_addr;
  447                         entry->rdr.alias_addr = rp->alias_addr;
  448                         entry->rdr.remote_addr = rp->remote_addr;
  449                         entry->rdr.local_port = rp->local_port;
  450                         entry->rdr.alias_port = rp->alias_port;
  451                         entry->rdr.remote_port = rp->remote_port;
  452                         entry->rdr.proto = rp->proto;
  453                         bcopy(rp->description, entry->rdr.description,
  454                             NG_NAT_DESC_LENGTH);
  455 
  456                         /* Safety precaution. */
  457                         entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
  458 
  459                         entry->rdr.id = priv->nextid++;
  460                         priv->rdrcount++;
  461 
  462                         /* Link to list of redirects. */
  463                         STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
  464 
  465                         /* Response with id of newly added entry. */
  466                         NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
  467                         if (resp == NULL) {
  468                                 error = ENOMEM;
  469                                 break;
  470                         }
  471                         bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
  472                     }
  473                         break;
  474                 case NGM_NAT_REDIRECT_ADDR:
  475                     {
  476                         struct ng_nat_rdr_lst *entry;
  477                         struct ng_nat_redirect_addr *const ra =
  478                             (struct ng_nat_redirect_addr *)msg->data;
  479 
  480                         if (msg->header.arglen < sizeof(*ra)) {
  481                                 error = EINVAL;
  482                                 break;
  483                         }
  484 
  485                         if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
  486                             M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
  487                                 error = ENOMEM;
  488                                 break;
  489                         }
  490 
  491                         /* Try actual redirect. */
  492                         entry->lnk = LibAliasRedirectAddr(priv->lib,
  493                                 ra->local_addr, ra->alias_addr);
  494 
  495                         if (entry->lnk == NULL) {
  496                                 error = ENOMEM;
  497                                 free(entry, M_NETGRAPH);
  498                                 break;
  499                         }
  500 
  501                         /* Successful, save info in our internal list. */
  502                         entry->rdr.local_addr = ra->local_addr;
  503                         entry->rdr.alias_addr = ra->alias_addr;
  504                         entry->rdr.proto = NG_NAT_REDIRPROTO_ADDR;
  505                         bcopy(ra->description, entry->rdr.description,
  506                             NG_NAT_DESC_LENGTH);
  507 
  508                         /* Safety precaution. */
  509                         entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
  510 
  511                         entry->rdr.id = priv->nextid++;
  512                         priv->rdrcount++;
  513 
  514                         /* Link to list of redirects. */
  515                         STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
  516 
  517                         /* Response with id of newly added entry. */
  518                         NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
  519                         if (resp == NULL) {
  520                                 error = ENOMEM;
  521                                 break;
  522                         }
  523                         bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
  524                     }
  525                         break;
  526                 case NGM_NAT_REDIRECT_PROTO:
  527                     {
  528                         struct ng_nat_rdr_lst *entry;
  529                         struct ng_nat_redirect_proto *const rp =
  530                             (struct ng_nat_redirect_proto *)msg->data;
  531 
  532                         if (msg->header.arglen < sizeof(*rp)) {
  533                                 error = EINVAL;
  534                                 break;
  535                         }
  536 
  537                         if ((entry = malloc(sizeof(struct ng_nat_rdr_lst),
  538                             M_NETGRAPH, M_NOWAIT | M_ZERO)) == NULL) {
  539                                 error = ENOMEM;
  540                                 break;
  541                         }
  542 
  543                         /* Try actual redirect. */
  544                         entry->lnk = LibAliasRedirectProto(priv->lib,
  545                                 rp->local_addr, rp->remote_addr,
  546                                 rp->alias_addr, rp->proto);
  547 
  548                         if (entry->lnk == NULL) {
  549                                 error = ENOMEM;
  550                                 free(entry, M_NETGRAPH);
  551                                 break;
  552                         }
  553 
  554                         /* Successful, save info in our internal list. */
  555                         entry->rdr.local_addr = rp->local_addr;
  556                         entry->rdr.alias_addr = rp->alias_addr;
  557                         entry->rdr.remote_addr = rp->remote_addr;
  558                         entry->rdr.proto = rp->proto;
  559                         bcopy(rp->description, entry->rdr.description,
  560                             NG_NAT_DESC_LENGTH);
  561 
  562                         /* Safety precaution. */
  563                         entry->rdr.description[NG_NAT_DESC_LENGTH-1] = '\0';
  564 
  565                         entry->rdr.id = priv->nextid++;
  566                         priv->rdrcount++;
  567 
  568                         /* Link to list of redirects. */
  569                         STAILQ_INSERT_TAIL(&priv->redirhead, entry, entries);
  570 
  571                         /* Response with id of newly added entry. */
  572                         NG_MKRESPONSE(resp, msg, sizeof(entry->rdr.id), M_NOWAIT);
  573                         if (resp == NULL) {
  574                                 error = ENOMEM;
  575                                 break;
  576                         }
  577                         bcopy(&entry->rdr.id, resp->data, sizeof(entry->rdr.id));
  578                     }
  579                         break;
  580                 case NGM_NAT_REDIRECT_DYNAMIC:
  581                 case NGM_NAT_REDIRECT_DELETE:
  582                     {
  583                         struct ng_nat_rdr_lst *entry;
  584                         uint32_t *const id = (uint32_t *)msg->data;
  585 
  586                         if (msg->header.arglen < sizeof(*id)) {
  587                                 error = EINVAL;
  588                                 break;
  589                         }
  590 
  591                         /* Find entry with supplied id. */
  592                         STAILQ_FOREACH(entry, &priv->redirhead, entries) {
  593                                 if (entry->rdr.id == *id)
  594                                         break;
  595                         }
  596 
  597                         /* Not found. */
  598                         if (entry == NULL) {
  599                                 error = ENOENT;
  600                                 break;
  601                         }
  602 
  603                         if (msg->header.cmd == NGM_NAT_REDIRECT_DYNAMIC) {
  604                                 if (LibAliasRedirectDynamic(priv->lib,
  605                                     entry->lnk) == -1) {
  606                                         error = ENOTTY; /* XXX Something better? */
  607                                         break;
  608                                 }
  609                         } else {        /* NGM_NAT_REDIRECT_DELETE */
  610                                 LibAliasRedirectDelete(priv->lib, entry->lnk);
  611                         }
  612 
  613                         /* Delete entry from our internal list. */
  614                         priv->rdrcount--;
  615                         STAILQ_REMOVE(&priv->redirhead, entry, ng_nat_rdr_lst, entries);
  616                         free(entry, M_NETGRAPH);
  617                     }
  618                         break;
  619                 case NGM_NAT_ADD_SERVER:
  620                     {
  621                         struct ng_nat_rdr_lst *entry;
  622                         struct ng_nat_add_server *const as =
  623                             (struct ng_nat_add_server *)msg->data;
  624 
  625                         if (msg->header.arglen < sizeof(*as)) {
  626                                 error = EINVAL;
  627                                 break;
  628                         }
  629 
  630                         /* Find entry with supplied id. */
  631                         STAILQ_FOREACH(entry, &priv->redirhead, entries) {
  632                                 if (entry->rdr.id == as->id)
  633                                         break;
  634                         }
  635 
  636                         /* Not found. */
  637                         if (entry == NULL) {
  638                                 error = ENOENT;
  639                                 break;
  640                         }
  641 
  642                         if (LibAliasAddServer(priv->lib, entry->lnk,
  643                             as->addr, htons(as->port)) == -1) {
  644                                 error = ENOMEM;
  645                                 break;
  646                         }
  647 
  648                         entry->rdr.lsnat++;
  649                     }
  650                         break;
  651                 case NGM_NAT_LIST_REDIRECTS:
  652                     {
  653                         struct ng_nat_rdr_lst *entry;
  654                         struct ng_nat_list_redirects *ary; 
  655                         int i = 0;
  656 
  657                         NG_MKRESPONSE(resp, msg, sizeof(*ary) +
  658                             (priv->rdrcount) * sizeof(*entry), M_NOWAIT);
  659                         if (resp == NULL) {
  660                                 error = ENOMEM;
  661                                 break;
  662                         }
  663 
  664                         ary = (struct ng_nat_list_redirects *)resp->data;
  665                         ary->total_count = priv->rdrcount;
  666 
  667                         STAILQ_FOREACH(entry, &priv->redirhead, entries) {
  668                                 bcopy(&entry->rdr, &ary->redirects[i++],
  669                                     sizeof(struct ng_nat_listrdrs_entry));
  670                         }
  671                     }
  672                         break;
  673                 case NGM_NAT_PROXY_RULE:
  674                     {
  675                         char *cmd = (char *)msg->data;
  676 
  677                         if (msg->header.arglen < 6) {
  678                                 error = EINVAL;
  679                                 break;
  680                         }
  681 
  682                         if (LibAliasProxyRule(priv->lib, cmd) != 0)
  683                                 error = ENOMEM;
  684                     }
  685                         break;
  686                 case NGM_NAT_LIBALIAS_INFO:
  687                     {
  688                         struct ng_nat_libalias_info *i;
  689 
  690                         NG_MKRESPONSE(resp, msg,
  691                             sizeof(struct ng_nat_libalias_info), M_NOWAIT);
  692                         if (resp == NULL) {
  693                                 error = ENOMEM;
  694                                 break;
  695                         }
  696                         i = (struct ng_nat_libalias_info *)resp->data;
  697 #define COPY(F) do {                                            \
  698         if (priv->lib->F >= 0 && priv->lib->F < UINT32_MAX)     \
  699                 i->F = priv->lib->F;                            \
  700         else                                                    \
  701                 i->F = UINT32_MAX;                              \
  702 } while (0)
  703                 
  704                         COPY(icmpLinkCount);
  705                         COPY(udpLinkCount);
  706                         COPY(tcpLinkCount);
  707                         COPY(pptpLinkCount);
  708                         COPY(sctpLinkCount);
  709                         COPY(protoLinkCount);
  710                         COPY(fragmentIdLinkCount);
  711                         COPY(fragmentPtrLinkCount);
  712                         COPY(sockCount);
  713 #undef COPY
  714                     }
  715                         break;
  716                 case NGM_NAT_SET_DLT:
  717                         if (msg->header.arglen != sizeof(uint8_t)) {
  718                                 error = EINVAL;
  719                                 break;
  720                         }
  721                         switch (*(uint8_t *) msg->data) {
  722                         case DLT_EN10MB:
  723                         case DLT_RAW:
  724                                 priv->dlt = *(uint8_t *) msg->data;
  725                                 break;
  726                         default:
  727                                 error = EINVAL;
  728                                 break;
  729                         }
  730                         break;
  731                 default:
  732                         error = EINVAL;         /* unknown command */
  733                         break;
  734                 }
  735                 break;
  736                 case NGM_NAT_GET_DLT:
  737                         NG_MKRESPONSE(resp, msg, sizeof(uint8_t), M_WAITOK);
  738                         if (resp == NULL) {
  739                                 error = ENOMEM;
  740                                 break;
  741                         }
  742                         *((uint8_t *) resp->data) = priv->dlt;
  743                         break;
  744         default:
  745                 error = EINVAL;                 /* unknown cookie type */
  746                 break;
  747         }
  748 
  749         NG_RESPOND_MSG(error, node, item, resp);
  750         NG_FREE_MSG(msg);
  751         return (error);
  752 }
  753 
  754 static int
  755 ng_nat_rcvdata(hook_p hook, item_p item )
  756 {
  757         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  758         struct mbuf     *m;
  759         struct ip       *ip;
  760         int rval, ipofs, error = 0;
  761         char *c;
  762 
  763         /* We have no required hooks. */
  764         if (!(priv->flags & NGNAT_CONNECTED)) {
  765                 NG_FREE_ITEM(item);
  766                 return (ENXIO);
  767         }
  768 
  769         /* We have no alias address yet to do anything. */
  770         if (!(priv->flags & NGNAT_ADDR_DEFINED))
  771                 goto send;
  772 
  773         m = NGI_M(item);
  774 
  775         if ((m = m_megapullup(m, m->m_pkthdr.len)) == NULL) {
  776                 NGI_M(item) = NULL;     /* avoid double free */
  777                 NG_FREE_ITEM(item);
  778                 return (ENOBUFS);
  779         }
  780 
  781         NGI_M(item) = m;
  782 
  783         switch (priv->dlt) {
  784         case DLT_RAW:
  785                 ipofs = 0;
  786                 break;
  787         case DLT_EN10MB:
  788             {
  789                 struct ether_header *eh;
  790 
  791                 if (m->m_pkthdr.len < sizeof(struct ether_header)) {
  792                         NG_FREE_ITEM(item);
  793                         return (ENXIO);
  794                 }
  795                 eh = mtod(m, struct ether_header *);
  796                 switch (ntohs(eh->ether_type)) {
  797                 case ETHERTYPE_IP:
  798                         ipofs = sizeof(struct ether_header);
  799                         break;
  800                 default:
  801                         goto send;
  802                 }
  803                 break;
  804             }
  805         default:
  806                 panic("Corrupted priv->dlt: %u", priv->dlt);
  807         }
  808 
  809         if (m->m_pkthdr.len < ipofs + sizeof(struct ip))
  810                 goto send;              /* packet too short to hold IP */
  811 
  812         c = (char *)mtodo(m, ipofs);
  813         ip = (struct ip *)mtodo(m, ipofs);
  814 
  815         if (ip->ip_v != IPVERSION)
  816                 goto send;              /* other IP version, let it pass */
  817         if (m->m_pkthdr.len < ipofs + ntohs(ip->ip_len))
  818                 goto send;              /* packet too short (i.e. fragmented or broken) */
  819 
  820         /*
  821          * We drop packet when:
  822          * 1. libalias returns PKT_ALIAS_ERROR;
  823          * 2. For incoming packets:
  824          *      a) for unresolved fragments;
  825          *      b) libalias returns PKT_ALIAS_IGNORED and
  826          *              PKT_ALIAS_DENY_INCOMING flag is set.
  827          */
  828         if (hook == priv->in) {
  829                 rval = LibAliasIn(priv->lib, c, m->m_len - ipofs +
  830                     M_TRAILINGSPACE(m));
  831                 if (rval == PKT_ALIAS_ERROR ||
  832                     rval == PKT_ALIAS_UNRESOLVED_FRAGMENT ||
  833                     (rval == PKT_ALIAS_IGNORED &&
  834                      (priv->lib->packetAliasMode &
  835                       PKT_ALIAS_DENY_INCOMING) != 0)) {
  836                         NG_FREE_ITEM(item);
  837                         return (EINVAL);
  838                 }
  839         } else if (hook == priv->out) {
  840                 rval = LibAliasOut(priv->lib, c, m->m_len - ipofs +
  841                     M_TRAILINGSPACE(m));
  842                 if (rval == PKT_ALIAS_ERROR) {
  843                         NG_FREE_ITEM(item);
  844                         return (EINVAL);
  845                 }
  846         } else
  847                 panic("ng_nat: unknown hook!\n");
  848 
  849         if (rval == PKT_ALIAS_RESPOND)
  850                 m->m_flags |= M_SKIP_FIREWALL;
  851         m->m_pkthdr.len = m->m_len = ntohs(ip->ip_len) + ipofs;
  852 
  853         if ((ip->ip_off & htons(IP_OFFMASK)) == 0 &&
  854             ip->ip_p == IPPROTO_TCP) {
  855                 struct tcphdr *th = (struct tcphdr *)((caddr_t)ip +
  856                     (ip->ip_hl << 2));
  857 
  858                 /*
  859                  * Here is our terrible HACK.
  860                  *
  861                  * Sometimes LibAlias edits contents of TCP packet.
  862                  * In this case it needs to recompute full TCP
  863                  * checksum. However, the problem is that LibAlias
  864                  * doesn't have any idea about checksum offloading
  865                  * in kernel. To workaround this, we do not do
  866                  * checksumming in LibAlias, but only mark the
  867                  * packets in th_x2 field. If we receive a marked
  868                  * packet, we calculate correct checksum for it
  869                  * aware of offloading.
  870                  *
  871                  * Why do I do such a terrible hack instead of
  872                  * recalculating checksum for each packet?
  873                  * Because the previous checksum was not checked!
  874                  * Recalculating checksums for EVERY packet will
  875                  * hide ALL transmission errors. Yes, marked packets
  876                  * still suffer from this problem. But, sigh, natd(8)
  877                  * has this problem, too.
  878                  */
  879 
  880                 if (th->th_x2) {
  881                         uint16_t ip_len = ntohs(ip->ip_len);
  882 
  883                         th->th_x2 = 0;
  884                         th->th_sum = in_pseudo(ip->ip_src.s_addr,
  885                             ip->ip_dst.s_addr, htons(IPPROTO_TCP +
  886                             ip_len - (ip->ip_hl << 2)));
  887         
  888                         if ((m->m_pkthdr.csum_flags & CSUM_TCP) == 0) {
  889                                 m->m_pkthdr.csum_data = offsetof(struct tcphdr,
  890                                     th_sum);
  891                                 in_delayed_cksum(m);
  892                         }
  893                 }
  894         }
  895 
  896 send:
  897         if (hook == priv->in)
  898                 NG_FWD_ITEM_HOOK(error, item, priv->out);
  899         else
  900                 NG_FWD_ITEM_HOOK(error, item, priv->in);
  901 
  902         return (error);
  903 }
  904 
  905 static int
  906 ng_nat_shutdown(node_p node)
  907 {
  908         const priv_p priv = NG_NODE_PRIVATE(node);
  909 
  910         NG_NODE_SET_PRIVATE(node, NULL);
  911         NG_NODE_UNREF(node);
  912 
  913         /* Free redirects list. */
  914         while (!STAILQ_EMPTY(&priv->redirhead)) {
  915                 struct ng_nat_rdr_lst *entry = STAILQ_FIRST(&priv->redirhead);
  916                 STAILQ_REMOVE_HEAD(&priv->redirhead, entries);
  917                 free(entry, M_NETGRAPH);
  918         }
  919 
  920         /* Final free. */
  921         LibAliasUninit(priv->lib);
  922         free(priv, M_NETGRAPH);
  923 
  924         return (0);
  925 }
  926 
  927 static int
  928 ng_nat_disconnect(hook_p hook)
  929 {
  930         const priv_p priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook));
  931 
  932         priv->flags &= ~NGNAT_CONNECTED;
  933 
  934         if (hook == priv->out)
  935                 priv->out = NULL;
  936         if (hook == priv->in)
  937                 priv->in = NULL;
  938 
  939         if (priv->out == NULL && priv->in == NULL)
  940                 ng_rmnode_self(NG_HOOK_NODE(hook));
  941 
  942         return (0);
  943 }
  944 
  945 static unsigned int
  946 ng_nat_translate_flags(unsigned int x)
  947 {
  948         unsigned int    res = 0;
  949         
  950         if (x & NG_NAT_LOG)
  951                 res |= PKT_ALIAS_LOG;
  952         if (x & NG_NAT_DENY_INCOMING)
  953                 res |= PKT_ALIAS_DENY_INCOMING;
  954         if (x & NG_NAT_SAME_PORTS)
  955                 res |= PKT_ALIAS_SAME_PORTS;
  956         if (x & NG_NAT_UNREGISTERED_ONLY)
  957                 res |= PKT_ALIAS_UNREGISTERED_ONLY;
  958         if (x & NG_NAT_RESET_ON_ADDR_CHANGE)
  959                 res |= PKT_ALIAS_RESET_ON_ADDR_CHANGE;
  960         if (x & NG_NAT_PROXY_ONLY)
  961                 res |= PKT_ALIAS_PROXY_ONLY;
  962         if (x & NG_NAT_REVERSE)
  963                 res |= PKT_ALIAS_REVERSE;
  964 
  965         return (res);
  966 }

Cache object: 6b8c8704bbb57b159b3114f308614d5c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.