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

Cache object: 8f90bc7bc3c2205dce697cdfd3114604


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