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

Cache object: 4095de212d8fc67b3835df8f3f37b435


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