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

Cache object: 06a635a4e279e6e4f3621ff4549b119c


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