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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3004c5201583e4d1a5e377fd9bd6d8a1


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