ng_nat.c (e842c54054b846061bf92d0f8a23ee3126ede6a9) ng_nat.c (fffba935e4085724c899c44c9fb5a10dede5016e)
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

--- 49 unchanged lines hidden (view full) ---

58
59static unsigned int ng_nat_translate_flags(unsigned int x);
60
61/* Parse type for struct ng_nat_mode. */
62static const struct ng_parse_struct_field ng_nat_mode_fields[]
63 = NG_NAT_MODE_INFO;
64static const struct ng_parse_type ng_nat_mode_type = {
65 &ng_parse_struct_type,
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

--- 49 unchanged lines hidden (view full) ---

58
59static unsigned int ng_nat_translate_flags(unsigned int x);
60
61/* Parse type for struct ng_nat_mode. */
62static const struct ng_parse_struct_field ng_nat_mode_fields[]
63 = NG_NAT_MODE_INFO;
64static const struct ng_parse_type ng_nat_mode_type = {
65 &ng_parse_struct_type,
66 ng_nat_mode_fields
66 &ng_nat_mode_fields
67};
68
67};
68
69/* Parse type for 'description' field in structs. */
70static const struct ng_parse_fixedstring_info ng_nat_description_info
71 = { NG_NAT_DESC_LENGTH };
72static 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. */
78static const struct ng_parse_struct_field ng_nat_redirect_port_fields[]
79 = NG_NAT_REDIRECT_PORT_TYPE_INFO(&ng_nat_description_type);
80static 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. */
86static const struct ng_parse_struct_field ng_nat_redirect_addr_fields[]
87 = NG_NAT_REDIRECT_ADDR_TYPE_INFO(&ng_nat_description_type);
88static 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. */
94static const struct ng_parse_struct_field ng_nat_redirect_proto_fields[]
95 = NG_NAT_REDIRECT_PROTO_TYPE_INFO(&ng_nat_description_type);
96static 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. */
102static const struct ng_parse_struct_field ng_nat_add_server_fields[]
103 = NG_NAT_ADD_SERVER_TYPE_INFO;
104static 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. */
110static const struct ng_parse_struct_field ng_nat_listrdrs_entry_fields[]
111 = NG_NAT_LISTRDRS_ENTRY_TYPE_INFO(&ng_nat_description_type);
112static 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. */
118static int
119ng_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
129static 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};
134static 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. */
140static const struct ng_parse_struct_field ng_nat_list_redirects_fields[]
141 = NG_NAT_LIST_REDIRECTS_TYPE_INFO(&ng_nat_listrdrs_ary_type);
142static const struct ng_parse_type ng_nat_list_redirects_type = {
143 &ng_parse_struct_type,
144 &ng_nat_list_redirects_fields
145};
146
69/* List of commands and how to convert arguments to/from ASCII. */
70static const struct ng_cmdlist ng_nat_cmdlist[] = {
71 {
72 NGM_NAT_COOKIE,
73 NGM_NAT_SET_IPADDR,
74 "setaliasaddr",
75 &ng_parse_ipaddr_type,
76 NULL

--- 7 unchanged lines hidden (view full) ---

84 },
85 {
86 NGM_NAT_COOKIE,
87 NGM_NAT_SET_TARGET,
88 "settarget",
89 &ng_parse_ipaddr_type,
90 NULL
91 },
147/* List of commands and how to convert arguments to/from ASCII. */
148static 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

--- 7 unchanged lines hidden (view full) ---

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 },
92 { 0 }
93};
94
95/* Netgraph node type descriptor. */
96static struct ng_type typestruct = {
97 .version = NG_ABI_VERSION,
98 .name = NG_NAT_NODE_TYPE,
99 .constructor = ng_nat_constructor,
100 .rcvmsg = ng_nat_rcvmsg,
101 .shutdown = ng_nat_shutdown,
102 .newhook = ng_nat_newhook,
103 .rcvdata = ng_nat_rcvdata,
104 .disconnect = ng_nat_disconnect,
105 .cmdlist = ng_nat_cmdlist,
106};
107NETGRAPH_INIT(nat, &typestruct);
108MODULE_DEPEND(ng_nat, libalias, 1, 1, 1);
109
226 { 0 }
227};
228
229/* Netgraph node type descriptor. */
230static 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};
241NETGRAPH_INIT(nat, &typestruct);
242MODULE_DEPEND(ng_nat, libalias, 1, 1, 1);
243
244/* Element for list of redirects. */
245struct 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};
250STAILQ_HEAD(rdrhead, ng_nat_rdr_lst);
251
110/* Information we store for each node. */
111struct ng_nat_priv {
112 node_p node; /* back pointer to node */
113 hook_p in; /* hook for demasquerading */
114 hook_p out; /* hook for masquerading */
115 struct libalias *lib; /* libalias handler */
116 uint32_t flags; /* status flags */
252/* Information we store for each node. */
253struct 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 */
117};
118typedef struct ng_nat_priv *priv_p;
119
120/* Values of flags */
121#define NGNAT_CONNECTED 0x1 /* We have both hooks connected */
122#define NGNAT_ADDR_DEFINED 0x2 /* NGM_NAT_SET_IPADDR happened */
123
124static int

--- 13 unchanged lines hidden (view full) ---

138 FREE(priv, M_NETGRAPH);
139 return (ENOMEM);
140 }
141
142 /* Set same ports on. */
143 (void )LibAliasSetMode(priv->lib, PKT_ALIAS_SAME_PORTS,
144 PKT_ALIAS_SAME_PORTS);
145
262};
263typedef 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
269static int

--- 13 unchanged lines hidden (view full) ---

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
146 /* Link structs together. */
147 NG_NODE_SET_PRIVATE(node, priv);
148 priv->node = node;
149
150 /*
151 * libalias is not thread safe, so our node
152 * must be single threaded.
153 */

--- 73 unchanged lines hidden (view full) ---

227 if (msg->header.arglen < sizeof(*ia)) {
228 error = EINVAL;
229 break;
230 }
231
232 LibAliasSetTarget(priv->lib, *ia);
233 }
234 break;
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 */

--- 73 unchanged lines hidden (view full) ---

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;
235 default:
236 error = EINVAL; /* unknown command */
237 break;
238 }
239 break;
240 default:
241 error = EINVAL; /* unknown cookie type */
242 break;

--- 111 unchanged lines hidden (view full) ---

354
355static int
356ng_nat_shutdown(node_p node)
357{
358 const priv_p priv = NG_NODE_PRIVATE(node);
359
360 NG_NODE_SET_PRIVATE(node, NULL);
361 NG_NODE_UNREF(node);
656 default:
657 error = EINVAL; /* unknown command */
658 break;
659 }
660 break;
661 default:
662 error = EINVAL; /* unknown cookie type */
663 break;

--- 111 unchanged lines hidden (view full) ---

775
776static int
777ng_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. */
362 LibAliasUninit(priv->lib);
363 FREE(priv, M_NETGRAPH);
364
365 return (0);
366}
367
368static int
369ng_nat_disconnect(hook_p hook)

--- 38 unchanged lines hidden ---
792 LibAliasUninit(priv->lib);
793 FREE(priv, M_NETGRAPH);
794
795 return (0);
796}
797
798static int
799ng_nat_disconnect(hook_p hook)

--- 38 unchanged lines hidden ---