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

Cache object: fbc230d76767ffa560105409aa711e04


[ 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.