Annotation of embedaddon/mpd/src/iface.c, revision 1.1.1.3
1.1 misho 1:
2: /*
3: * iface.c
4: *
5: * Written by Archie Cobbs <archie@freebsd.org>
6: * Copyright (c) 1995-1999 Whistle Communications, Inc. All rights reserved.
7: * See ``COPYRIGHT.whistle''
8: *
9: * TCP MSSFIX code copyright (c) 2000 Ruslan Ermilov
10: * TCP MSSFIX contributed by Sergey Korolew <dsATbittu.org.ru>
11: *
12: */
13:
14: #include "ppp.h"
15: #include "iface.h"
16: #include "ipcp.h"
17: #include "auth.h"
18: #include "ngfunc.h"
19: #include "netgraph.h"
20: #include "util.h"
21:
1.1.1.2 misho 22: #include <sys/types.h>
1.1 misho 23: #include <sys/sockio.h>
24: #include <sys/sysctl.h>
1.1.1.2 misho 25: #include <sys/param.h>
1.1 misho 26: #include <net/if.h>
27: #include <net/if_types.h>
28: #include <net/if_dl.h>
29: #include <net/if_var.h>
30: #include <net/route.h>
31: #include <netinet/in_systm.h>
32: #include <netinet/in.h>
33: #include <netinet/in_var.h>
34: #include <netinet/if_ether.h>
35: #include <netinet6/nd6.h>
36: #include <netgraph/ng_message.h>
37: #include <netgraph/ng_iface.h>
38: #ifdef USE_NG_BPF
39: #include <netgraph/ng_bpf.h>
40: #endif
41: #include <netgraph/ng_tee.h>
42: #include <netgraph/ng_ksocket.h>
43: #include <netinet/ip_icmp.h>
44: #include <netinet/tcp.h>
45: #include <netinet/udp.h>
46: #ifdef USE_NG_TCPMSS
47: #include <netgraph/ng_tcpmss.h>
48: #endif
49: #ifdef USE_NG_IPACCT
50: #include <netgraph/ng_ipacct.h>
51: #undef r_ip_p /* XXX:DIRTY CONFLICT! */
52: #endif
53: #ifdef USE_NG_NETFLOW
54: #include <netgraph/netflow/ng_netflow.h>
55: #endif
56: #ifdef USE_NG_CAR
57: #include <netgraph/ng_car.h>
58: #endif
59:
60: #ifdef USE_NG_BPF
61: #include <pcap.h>
62: #endif
63:
1.1.1.2 misho 64: #include <string.h>
65:
1.1 misho 66: /*
67: * DEFINITIONS
68: */
69:
70: /* Set menu options */
71:
72: enum {
73: SET_IDLE,
74: SET_SESSION,
75: SET_ADDRS,
76: SET_ROUTE,
77: SET_MTU,
78: SET_NAME,
79: #ifdef SIOCSIFDESCR
80: SET_DESCR,
81: #endif
82: #ifdef SIOCAIFGROUP
83: SET_GROUP,
84: #endif
85: SET_UP_SCRIPT,
86: SET_DOWN_SCRIPT,
87: SET_ENABLE,
88: SET_DISABLE
89: };
90:
91: /*
92: * INTERNAL FUNCTIONS
93: */
94:
95: static int IfaceNgIpInit(Bund b, int ready);
96: static void IfaceNgIpShutdown(Bund b);
97: static int IfaceNgIpv6Init(Bund b, int ready);
98: static void IfaceNgIpv6Shutdown(Bund b);
99:
100: #ifdef USE_NG_NETFLOW
1.1.1.2 misho 101: static int IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out, int v6);
1.1.1.3 ! misho 102: static int IfaceSetupNetflow(Bund b, char in, char out, int v6);
! 103: static void IfaceShutdownNetflow(Bund b, char in, char out, int v6);
1.1 misho 104: #endif
105:
106: #ifdef USE_NG_IPACCT
107: static int IfaceInitIpacct(Bund b, char *path, char *hook);
108: static void IfaceShutdownIpacct(Bund b);
109: #endif
110:
111: #ifdef USE_NG_NAT
112: static int IfaceInitNAT(Bund b, char *path, char *hook);
113: static int IfaceSetupNAT(Bund b);
114: static void IfaceShutdownNAT(Bund b);
115: #endif
116:
117: static int IfaceInitTee(Bund b, char *path, char *hook, int v6);
118: static void IfaceShutdownTee(Bund b, int v6);
119:
120: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
121: static int IfaceInitMSS(Bund b, char *path, char *hook);
122: static void IfaceSetupMSS(Bund b, uint16_t maxMSS);
123: static void IfaceShutdownMSS(Bund b);
124: #endif
125:
126: #ifdef USE_NG_BPF
127: static int IfaceInitLimits(Bund b, char *path, char *hook);
128: static void IfaceSetupLimits(Bund b);
129: static void IfaceShutdownLimits(Bund b);
130: #endif
131:
132: static int IfaceSetCommand(Context ctx, int ac, char *av[], void *arg);
133: static void IfaceSessionTimeout(void *arg);
134: static void IfaceIdleTimeout(void *arg);
135:
136: static void IfaceCacheSend(Bund b);
137: static void IfaceCachePkt(Bund b, int proto, Mbuf pkt);
138: static int IfaceIsDemand(int proto, Mbuf pkt);
139:
140: #ifdef USE_IPFW
141: static int IfaceAllocACL (struct acl_pool ***ap, int start, char * ifname, int number);
142: static int IfaceFindACL (struct acl_pool *ap, char * ifname, int number);
1.1.1.3 ! misho 143: static char * IfaceParseACL (char * src, IfaceState iface);
1.1 misho 144: #endif
145:
146: static int IfaceSetName(Bund b, const char * ifname);
147: #ifdef SIOCSIFDESCR
148: static int IfaceSetDescr(Bund b, const char * ifdescr);
1.1.1.2 misho 149: static void IfaceFreeDescr(IfaceState iface);
1.1 misho 150: #endif
151: #ifdef SIOCAIFGROUP
152: static int IfaceAddGroup(Bund b, const char * ifgroup);
153: static int IfaceDelGroup(Bund b, const char * ifgroup);
154: #endif
155: /*
156: * GLOBAL VARIABLES
157: */
158:
159: const struct cmdtab IfaceSetCmds[] = {
160: { "addrs {self} {peer}", "Set interface addresses",
161: IfaceSetCommand, NULL, 2, (void *) SET_ADDRS },
162: { "route {dest}[/{width}]", "Add IP route",
163: IfaceSetCommand, NULL, 2, (void *) SET_ROUTE },
164: { "mtu {size}", "Set max allowed interface MTU",
165: IfaceSetCommand, NULL, 2, (void *) SET_MTU },
166: { "name [{name}]", "Set interface name",
167: IfaceSetCommand, NULL, 2, (void *) SET_NAME },
168: #ifdef SIOCSIFDESCR
169: { "description [{descr}]", "Set interface description",
170: IfaceSetCommand, NULL, 2, (void *) SET_DESCR },
171: #endif
172: #ifdef SIOCAIFGROUP
173: { "group [{group}]", "Set interface group",
174: IfaceSetCommand, NULL, 2, (void *) SET_GROUP },
175: #endif
176: { "up-script [{progname}]", "Interface up script",
177: IfaceSetCommand, NULL, 2, (void *) SET_UP_SCRIPT },
178: { "down-script [{progname}]", "Interface down script",
179: IfaceSetCommand, NULL, 2, (void *) SET_DOWN_SCRIPT },
180: #ifdef USE_NG_BPF
181: { "idle {seconds}", "Idle timeout",
182: IfaceSetCommand, NULL, 2, (void *) SET_IDLE },
183: #endif
184: { "session {seconds}", "Session timeout",
185: IfaceSetCommand, NULL, 2, (void *) SET_SESSION },
186: { "enable [opt ...]", "Enable option",
187: IfaceSetCommand, NULL, 2, (void *) SET_ENABLE },
188: { "disable [opt ...]", "Disable option",
189: IfaceSetCommand, NULL, 2, (void *) SET_DISABLE },
190: { NULL },
191: };
192:
193: /*
194: * INTERNAL VARIABLES
195: */
196:
197: static const struct confinfo gConfList[] = {
198: { 0, IFACE_CONF_ONDEMAND, "on-demand" },
199: { 0, IFACE_CONF_PROXY, "proxy-arp" },
1.1.1.3 ! misho 200: { 0, IFACE_CONF_KEEP_TIMEOUT, "keep-timeout" },
1.1 misho 201: #ifdef USE_NG_TCPMSS
202: { 0, IFACE_CONF_TCPMSSFIX, "tcpmssfix" },
203: #endif
204: { 0, IFACE_CONF_TEE, "tee" },
205: #ifdef USE_NG_NAT
206: { 0, IFACE_CONF_NAT, "nat" },
207: #endif
208: #ifdef USE_NG_NETFLOW
209: { 0, IFACE_CONF_NETFLOW_IN, "netflow-in" },
210: { 0, IFACE_CONF_NETFLOW_OUT, "netflow-out" },
211: #ifdef NG_NETFLOW_CONF_ONCE
212: { 0, IFACE_CONF_NETFLOW_ONCE, "netflow-once" },
213: #endif
214: #endif
215: #ifdef USE_NG_IPACCT
216: { 0, IFACE_CONF_IPACCT, "ipacct" },
217: #endif
218: { 0, 0, NULL },
219: };
220:
221: #ifdef USE_IPFW
222: struct acl_pool * rule_pool = NULL; /* Pointer to the first element in the list of rules */
223: struct acl_pool * pipe_pool = NULL; /* Pointer to the first element in the list of pipes */
224: struct acl_pool * queue_pool = NULL; /* Pointer to the first element in the list of queues */
225: struct acl_pool * table_pool = NULL; /* Pointer to the first element in the list of tables */
226: int rule_pool_start = 10000; /* Initial number of ipfw rules pool */
227: int pipe_pool_start = 10000; /* Initial number of ipfw dummynet pipe pool */
228: int queue_pool_start = 10000; /* Initial number of ipfw dummynet queue pool */
229: int table_pool_start = 32; /* Initial number of ipfw tables pool */
230: #endif
231:
232: #ifdef USE_NG_BPF
233: /* A BPF filter that matches TCP SYN packets */
1.1.1.3 ! misho 234: static const struct bpf_insn gTCPSYNProg[] __attribute__((used)) = {
1.1 misho 235: /*00*/ BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 9), /* A <- IP protocol */
236: /*01*/ BPF_JUMP(BPF_JMP+BPF_JEQ+BPF_K, IPPROTO_TCP, 0, 6), /* !TCP => 8 */
237: /*02*/ BPF_STMT(BPF_LD+BPF_H+BPF_ABS, 6), /* A <- fragmentation offset */
238: /*03*/ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, 0x1fff, 4, 0), /* fragment => 8 */
239: /*04*/ BPF_STMT(BPF_LDX+BPF_B+BPF_MSH, 0), /* X <- header len */
240: /*05*/ BPF_STMT(BPF_LD+BPF_B+BPF_IND, 13), /* A <- TCP flags */
241: /*06*/ BPF_JUMP(BPF_JMP+BPF_JSET+BPF_K, TH_SYN, 0, 1), /* !TH_SYN => 8 */
242: /*07*/ BPF_STMT(BPF_RET+BPF_K, (u_int)-1), /* accept packet */
243: /*08*/ BPF_STMT(BPF_RET+BPF_K, 0), /* reject packet */
244: };
245:
246: #define TCPSYN_PROG_LEN (sizeof(gTCPSYNProg) / sizeof(*gTCPSYNProg))
247:
248: /* A BPF filter that matches nothing */
249: static const struct bpf_insn gNoMatchProg[] = {
250: BPF_STMT(BPF_RET+BPF_K, 0)
251: };
252:
253: #define NOMATCH_PROG_LEN (sizeof(gNoMatchProg) / sizeof(*gNoMatchProg))
254:
255: /* A BPF filter that matches everything */
256: static const struct bpf_insn gMatchProg[] = {
257: BPF_STMT(BPF_RET+BPF_K, (u_int)-1)
258: };
259:
260: #define MATCH_PROG_LEN (sizeof(gMatchProg) / sizeof(*gMatchProg))
261: #endif /* USE_NG_BPF */
262:
263: #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
264: 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
265: static const struct in6_addr in6mask128 = IN6MASK128;
266:
1.1.1.2 misho 267: #ifdef SIOCSIFDESCR
268: void
269: IfaceFreeDescr(IfaceState iface)
270: {
271: if (iface->ifdescr != NULL)
272: Freee(iface->ifdescr);
273: if (iface->conf.ifdescr != NULL)
274: Freee(iface->conf.ifdescr);
275: iface->ifdescr = iface->conf.ifdescr = NULL;
276: }
277: #endif
1.1 misho 278:
279: /*
280: * IfaceInit()
281: */
282:
283: void
284: IfaceInit(Bund b)
285: {
286: IfaceState const iface = &b->iface;
287:
288: /* Default configuration */
289: iface->mtu = NG_IFACE_MTU_DEFAULT;
290: iface->max_mtu = NG_IFACE_MTU_DEFAULT;
291: #ifdef SIOCSIFDESCR
292: iface->ifdescr = NULL;
293: iface->conf.ifdescr = NULL;
294: #endif
295: Disable(&iface->options, IFACE_CONF_ONDEMAND);
296: Disable(&iface->options, IFACE_CONF_PROXY);
1.1.1.3 ! misho 297: Disable(&iface->options, IFACE_CONF_KEEP_TIMEOUT);
1.1 misho 298: Disable(&iface->options, IFACE_CONF_TCPMSSFIX);
299: #ifdef USE_NG_NAT
300: NatInit(b);
301: #endif
302: #ifdef USE_NG_BPF
303: SLIST_INIT(&iface->ss[0]);
304: SLIST_INIT(&iface->ss[1]);
305: #endif
306: }
307:
308: /*
309: * IfaceInst()
310: */
311:
312: void
313: IfaceInst(Bund b, Bund bt)
314: {
315: IfaceState const iface = &b->iface;
316:
317: memcpy(iface, &bt->iface, sizeof(*iface));
318:
1.1.1.2 misho 319: #ifdef SIOCSIFDESCR
320: /* Copy interface description from template config to current */
321: if (bt->iface.conf.ifdescr)
322: iface->conf.ifdescr = Mstrdup(MB_IFACE, bt->iface.conf.ifdescr);
323: if (bt->iface.ifdescr)
324: iface->ifdescr = Mstrdup(MB_IFACE, bt->iface.ifdescr);
325: #endif
1.1 misho 326: /* Copy interface name from template config to current */
327: if (bt->iface.conf.ifname[0] != 0 && b->tmpl == 0) {
328: snprintf(iface->conf.ifname, sizeof(iface->conf.ifname), "%s%d",
329: bt->iface.conf.ifname, b->id);
330: Log(LG_IFACE2, ("[%s] IFACE: Set conf.ifname to ", iface->conf.ifname));
331: }
332: }
333:
334: /*
335: * IfaceDestroy()
336: */
337:
338: void
339: IfaceDestroy(Bund b)
340: {
341: #ifdef SIOCSIFDESCR
342: IfaceState const iface = &b->iface;
343:
1.1.1.2 misho 344: IfaceFreeDescr(iface);
1.1 misho 345: #endif
346: }
347:
348: /*
349: * IfaceOpen()
350: *
351: * Open the interface layer
352: */
353:
354: void
355: IfaceOpen(Bund b)
356: {
357: IfaceState const iface = &b->iface;
358:
359: Log(LG_IFACE, ("[%s] IFACE: Open event", b->name));
360:
361: /* Open is useless without on-demand. */
362: if (!Enabled(&iface->options, IFACE_CONF_ONDEMAND)) {
363: Log(LG_ERR, ("[%s] 'open iface' is useless without on-demand enabled", b->name));
364: return;
365: }
366:
367: /* If interface is already open do nothing */
368: if (iface->open)
369: return;
370: iface->open = TRUE;
371:
372: /* If on-demand, bring up system interface immediately and start
373: listening for outgoing packets. The next outgoing packet will
374: cause us to open the lower layer(s) */
375: BundNcpsJoin(b, NCP_NONE);
376: }
377:
378: /*
379: * IfaceClose()
380: *
381: * Close the interface layer
382: */
383:
384: void
385: IfaceClose(Bund b)
386: {
387: IfaceState const iface = &b->iface;
388:
389: Log(LG_IFACE, ("[%s] IFACE: Close event", b->name));
390:
391: /* If interface is already closed do nothing */
392: if (!iface->open)
393: return;
394: iface->open = FALSE;
395:
396: /* If there was on-demand, tell that it is not needed anymore */
397: BundNcpsLeave(b, NCP_NONE);
398: }
399:
400: /*
401: * IfaceOpenCmd()
402: *
403: * Open the interface layer
404: */
405:
406: int
407: IfaceOpenCmd(Context ctx)
408: {
409: if (ctx->bund->tmpl)
410: Error("impossible to open template");
411: IfaceOpen(ctx->bund);
412: return (0);
413: }
414:
415: /*
416: * IfaceCloseCmd()
417: *
418: * Close the interface layer
419: */
420:
421: int
422: IfaceCloseCmd(Context ctx)
423: {
424: if (ctx->bund->tmpl)
425: Error("impossible to close template");
426: IfaceClose(ctx->bund);
427: return (0);
428: }
429:
430: /*
431: * IfaceUp()
432: *
433: * Our underlying PPP bundle is ready for traffic.
434: * We may signal that the interface is in DoD with the IFF_LINK0 flag.
435: */
436:
437: void
438: IfaceUp(Bund b, int ready)
439: {
440: IfaceState const iface = &b->iface;
441: int session_timeout = 0, idle_timeout = 0;
442: #ifdef USE_IPFW
443: struct acl *acls, *acl;
444: char *buf;
445: struct acl_pool **poollast;
446: int poollaststart;
447: int prev_number;
448: int prev_real_number;
449: #endif
450:
451: Log(LG_IFACE, ("[%s] IFACE: Up event", b->name));
452: iface->last_up = time(NULL);
453:
454: if (ready) {
455:
456: /* Start Session timer */
457: if (b->params.session_timeout > 0) {
1.1.1.3 ! misho 458: if (Enabled(&iface->options, IFACE_CONF_KEEP_TIMEOUT)) {
! 459: session_timeout = b->params.session_timeout - \
! 460: (iface->last_up - b->last_up);
! 461: Log(LG_IFACE2, ("[%s] IFACE: keep session-timeout at: %d seconds",
! 462: b->name, session_timeout));
! 463: } else {
! 464: session_timeout = b->params.session_timeout;
! 465: }
1.1 misho 466: } else if (iface->session_timeout > 0) {
467: session_timeout = iface->session_timeout;
468: }
469:
470: if (session_timeout > 0) {
471: Log(LG_IFACE2, ("[%s] IFACE: session-timeout: %d seconds",
472: b->name, session_timeout));
473: if (session_timeout > INT_MAX / 1100) {
474: session_timeout = INT_MAX / 1100;
475: Log(LG_ERR, ("[%s] IFACE: session-timeout limited to %d seconds",
1.1.1.3 ! misho 476: b->name, session_timeout));
1.1 misho 477: }
478: TimerInit(&iface->sessionTimer, "IfaceSession",
479: session_timeout * SECONDS, IfaceSessionTimeout, b);
480: TimerStart(&iface->sessionTimer);
481: }
482:
483: /* Start idle timer */
484: if (b->params.idle_timeout > 0) {
485: idle_timeout = b->params.idle_timeout;
486: } else if (iface->idle_timeout > 0) {
487: idle_timeout = iface->idle_timeout;
488: }
489:
490: if (idle_timeout > 0) {
491: Log(LG_IFACE2, ("[%s] IFACE: idle-timeout: %d seconds",
492: b->name, idle_timeout));
493: if (idle_timeout > INT_MAX / 1100 * IFACE_IDLE_SPLIT) {
494: idle_timeout = INT_MAX / 1100 * IFACE_IDLE_SPLIT;
495: Log(LG_ERR, ("[%s] IFACE: idle-timeout limited to %d seconds",
496: b->name, idle_timeout));
497: }
498: TimerInit(&iface->idleTimer, "IfaceIdle",
499: idle_timeout * SECONDS / IFACE_IDLE_SPLIT, IfaceIdleTimeout, b);
500: TimerStart(&iface->idleTimer);
501: iface->traffic[1] = TRUE;
502: iface->traffic[0] = FALSE;
503:
504: /* Reset statistics */
505: memset(&iface->idleStats, 0, sizeof(iface->idleStats));
506: }
507:
508: /* Update interface name and description */
509: if (b->params.ifname[0] != 0) {
510: if (IfaceSetName(b, b->params.ifname) != -1)
511: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
512: b->name, iface->ngname, b->params.ifname));
513: } else if (iface->conf.ifname[0] != 0) {
514: if (IfaceSetName(b, iface->conf.ifname) != -1)
515: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
516: b->name, iface->ngname, iface->conf.ifname));
517: }
518: #ifdef SIOCSIFDESCR
519: if (b->params.ifdescr != NULL) {
520: if (IfaceSetDescr(b, b->params.ifdescr) != -1) {
521: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"",
1.1.1.2 misho 522: b->name, iface->ifdescr));
523: }
524: } else if (iface->conf.ifdescr != NULL) {
525: if (IfaceSetDescr(b, iface->conf.ifdescr) != -1) {
526: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add description \"%s\"",
527: b->name, iface->ifdescr));
1.1 misho 528: }
529: }
530: #endif
531: #ifdef SIOCAIFGROUP
532: if (iface->conf.ifgroup[0] != 0) {
533: if (IfaceAddGroup(b, iface->conf.ifgroup) != -1)
534: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add group %s to %s",
535: b->name, iface->conf.ifgroup, iface->ngname));
536: }
537: if (b->params.ifgroup[0] != 0) {
538: if (IfaceAddGroup(b, b->params.ifgroup) != -1)
539: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Add group %s to %s",
540: b->name, b->params.ifgroup, iface->ngname));
541: }
542: #endif
543: #ifdef USE_IPFW
544: /* Allocate ACLs */
545: acls = b->params.acl_pipe;
546: poollast = &pipe_pool;
547: poollaststart = pipe_pool_start;
548: while (acls != NULL) {
549: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
550: poollaststart = acls->real_number;
551: acls = acls->next;
552: };
553: acls = b->params.acl_queue;
554: poollast = &queue_pool;
555: poollaststart = queue_pool_start;
556: while (acls != NULL) {
557: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
558: poollaststart = acls->real_number;
559: acls = acls->next;
560: };
561: prev_number = -1;
562: prev_real_number = -1;
563: acls = b->params.acl_table;
564: poollast = &table_pool;
565: poollaststart = table_pool_start;
566: while (acls != NULL) {
567: if (acls->real_number == 0) {
568: if (acls->number == prev_number) { /* ACL list is presorted so we need not allocate if equal */
569: acls->real_number = prev_real_number;
570: } else {
571: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
572: poollaststart = acls->real_number;
573: prev_number = acls->number;
574: prev_real_number = acls->real_number;
575: }
576: }
577: acls = acls->next;
578: };
579: acls = b->params.acl_rule;
580: poollast = &rule_pool;
581: poollaststart = rule_pool_start;
582: while (acls != NULL) {
583: acls->real_number = IfaceAllocACL(&poollast, poollaststart, iface->ifname, acls->number);
584: poollaststart = acls->real_number;
585: acls = acls->next;
586: };
587:
588: /* Set ACLs */
589: acls = b->params.acl_pipe;
590: while (acls != NULL) {
591: ExecCmd(LG_IFACE2, b->name, "%s pipe %d config %s", PATH_IPFW, acls->real_number, acls->rule);
592: acls = acls->next;
593: }
594: acls = b->params.acl_queue;
595: while (acls != NULL) {
1.1.1.3 ! misho 596: buf = IfaceParseACL(acls->rule, iface);
1.1 misho 597: ExecCmd(LG_IFACE2, b->name, "%s queue %d config %s", PATH_IPFW, acls->real_number, buf);
598: Freee(buf);
599: acls = acls->next;
600: }
601: acls = b->params.acl_table;
602: while (acls != NULL) {
1.1.1.3 ! misho 603: /* allow both %aX and `peer_addr` macros */
! 604: buf = IfaceParseACL(acls->rule, iface);
! 605: strcpy(acls->rule, buf);
! 606: Freee(buf);
1.1.1.2 misho 607: acl = Mdup(MB_IPFW, acls, sizeof(struct acl) + strlen(acls->rule));
1.1 misho 608: acl->next = iface->tables;
609: iface->tables = acl;
1.1.1.3 ! misho 610: if (strncmp(acls->rule, "peer_addr", 9) == 0) {
! 611: char hisaddr[20];
! 612: ExecCmd(LG_IFACE2, b->name, "%s table %d add %s",
! 613: PATH_IPFW, acls->real_number,
! 614: u_addrtoa(&iface->peer_addr, hisaddr, sizeof(hisaddr)));
! 615: } else {
! 616: ExecCmd(LG_IFACE2, b->name, "%s table %d add %s", PATH_IPFW, acls->real_number, acls->rule);
! 617: }
1.1 misho 618: acls = acls->next;
619: };
620: acls = b->params.acl_rule;
621: while (acls != NULL) {
1.1.1.3 ! misho 622: buf = IfaceParseACL(acls->rule, iface);
1.1 misho 623: ExecCmd(LG_IFACE2, b->name, "%s add %d %s via %s", PATH_IPFW, acls->real_number, buf, iface->ifname);
624: Freee(buf);
625: acls = acls->next;
626: };
627: #endif /* USE_IPFW */
628:
629: };
630:
631: /* Bring up system interface */
632: IfaceChangeFlags(b, 0, IFF_UP | (ready?0:IFF_LINK0));
633:
634: /* Send any cached packets */
635: IfaceCacheSend(b);
636:
637: }
638:
639: /*
640: * IfaceDown()
641: *
642: * Our packet transport mechanism is no longer ready for traffic.
643: */
644:
645: void
646: IfaceDown(Bund b)
647: {
648: IfaceState const iface = &b->iface;
649: #ifdef USE_IPFW
650: struct acl_pool **rp, *rp1;
651: char cb[32768];
652: struct acl *acl, *aclnext;
653: #endif
654:
655: Log(LG_IFACE, ("[%s] IFACE: Down event", b->name));
656:
657: /* Bring down system interface */
658: IfaceChangeFlags(b, IFF_UP | IFF_LINK0, 0);
659:
660: TimerStop(&iface->idleTimer);
661: TimerStop(&iface->sessionTimer);
662:
663: #ifdef USE_IPFW
664: /* Remove rule ACLs */
665: rp = &rule_pool;
666: cb[0]=0;
667: while (*rp != NULL) {
668: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
669: sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
670: rp1 = *rp;
671: *rp = (*rp)->next;
672: Freee(rp1);
673: } else {
674: rp = &((*rp)->next);
675: };
676: };
677: if (cb[0]!=0)
678: ExecCmdNosh(LG_IFACE2, b->name, "%s delete%s",
679: PATH_IPFW, cb);
680:
681: /* Remove table ACLs */
682: rp = &table_pool;
683: while (*rp != NULL) {
684: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
685: rp1 = *rp;
686: *rp = (*rp)->next;
687: Freee(rp1);
688: } else {
689: rp = &((*rp)->next);
690: };
691: };
692: acl = iface->tables;
693: while (acl != NULL) {
1.1.1.3 ! misho 694: if (strncmp(acl->rule, "peer_addr", 9) == 0) {
! 695: char hisaddr[20];
! 696: ExecCmd(LG_IFACE2, b->name, "%s table %d delete %s",
! 697: PATH_IPFW, acl->real_number,
! 698: u_addrtoa(&iface->peer_addr, hisaddr, sizeof(hisaddr)));
! 699: } else {
! 700: ExecCmd(LG_IFACE2, b->name, "%s table %d delete %s",
! 701: PATH_IPFW, acl->real_number, acl->rule);
! 702: }
1.1 misho 703: aclnext = acl->next;
704: Freee(acl);
705: acl = aclnext;
706: };
707: iface->tables = NULL;
708:
709: /* Remove queue ACLs */
710: rp = &queue_pool;
711: cb[0]=0;
712: while (*rp != NULL) {
713: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
714: sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
715: rp1 = *rp;
716: *rp = (*rp)->next;
717: Freee(rp1);
718: } else {
719: rp = &((*rp)->next);
720: };
721: };
722: if (cb[0]!=0)
723: ExecCmdNosh(LG_IFACE2, b->name, "%s queue delete%s",
724: PATH_IPFW, cb);
725:
726: /* Remove pipe ACLs */
727: rp = &pipe_pool;
728: cb[0]=0;
729: while (*rp != NULL) {
730: if (strncmp((*rp)->ifname, iface->ifname, IFNAMSIZ) == 0) {
731: sprintf(cb+strlen(cb), " %d", (*rp)->real_number);
732: rp1 = *rp;
733: *rp = (*rp)->next;
734: Freee(rp1);
735: } else {
736: rp = &((*rp)->next);
737: };
738: };
739: if (cb[0]!=0)
740: ExecCmdNosh(LG_IFACE2, b->name, "%s pipe delete%s",
741: PATH_IPFW, cb);
742: #endif /* USE_IPFW */
743:
1.1.1.2 misho 744: /* Clearing self and peer addresses */
745: u_rangeclear(&iface->self_addr);
746: u_addrclear(&iface->peer_addr);
747: u_addrclear(&iface->self_ipv6_addr);
748: u_addrclear(&iface->peer_ipv6_addr);
749:
1.1 misho 750: /* Revert interface name and description */
751:
752: if (strcmp(iface->ngname, iface->ifname) != 0) {
753: if (iface->conf.ifname[0] != 0) {
754: /* Restore to config defined */
755: if (IfaceSetName(b, iface->conf.ifname) != -1)
756: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
757: b->name, iface->ifname, iface->conf.ifname));
758: } else {
759: /* Restore to original interface name */
760: if (IfaceSetName(b, iface->ngname) != -1)
761: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Rename interface %s to %s",
762: b->name, iface->ifname, iface->ngname));
763: }
764: }
765: #ifdef SIOCSIFDESCR
1.1.1.2 misho 766: if ((iface->ifdescr != NULL)
767: && (IfaceSetDescr(b, iface->conf.ifdescr) != -1)) {
1.1 misho 768: if (iface->conf.ifdescr != NULL) {
769: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Set description \"%s\"",
1.1.1.2 misho 770: b->name, iface->ifdescr));
1.1 misho 771: } else {
772: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Clear description",
773: b->name));
774: }
775: }
776: #endif
777: #ifdef SIOCAIFGROUP
778: if (b->params.ifgroup[0] != 0) {
779: if (IfaceDelGroup(b, b->params.ifgroup) != -1)
780: Log(LG_BUND|LG_IFACE, ("[%s] IFACE: Remove group %s from %s",
781: b->name, b->params.ifgroup, iface->ngname));
782: }
783: #endif
784: }
785:
786: /*
787: * IfaceListenInput()
788: *
789: * A packet was received on our demand snooping hook. Stimulate a connection.
790: */
791:
792: void
793: IfaceListenInput(Bund b, int proto, Mbuf pkt)
794: {
795: IfaceState const iface = &b->iface;
796: int const isDemand = IfaceIsDemand(proto, pkt);
797:
798: /* Does this count as demand traffic? */
799: if (iface->open && isDemand) {
800: iface->traffic[0] = TRUE;
801: Log(LG_IFACE, ("[%s] IFACE: Outgoing %s packet demands connection", b->name,
802: (proto==PROTO_IP)?"IP":"IPv6"));
803: RecordLinkUpDownReason(b, NULL, 1, STR_DEMAND, NULL);
804: BundOpen(b);
805: IfaceCachePkt(b, proto, pkt);
806: } else {
807: mbfree(pkt);
808: }
809: }
810:
811: #ifdef USE_IPFW
812: /*
813: * IfaceAllocACL ()
814: *
815: * Allocates unique real number for new ACL and adds it to the list of used ones.
816: */
817:
818: static int
819: IfaceAllocACL(struct acl_pool ***ap, int start, char *ifname, int number)
820: {
821: int i;
822: struct acl_pool **rp,*rp1;
823:
1.1.1.2 misho 824: rp1 = Malloc(MB_IPFW, sizeof(struct acl_pool));
1.1 misho 825: strlcpy(rp1->ifname, ifname, sizeof(rp1->ifname));
826: rp1->acl_number = number;
827:
828: rp = *ap;
829: i = start;
830: while (*rp != NULL && (*rp)->real_number <= i) {
831: i = (*rp)->real_number+1;
832: rp = &((*rp)->next);
833: };
834: if (*rp == NULL) {
835: rp1->next = NULL;
836: } else {
837: rp1->next = *rp;
838: };
839: rp1->real_number = i;
840: *rp = rp1;
841: *ap = rp;
842: return(i);
843: }
844:
845: /*
846: * IfaceFindACL ()
847: *
848: * Finds ACL in the list and gets its real number.
849: */
850:
851: static int
852: IfaceFindACL (struct acl_pool *ap, char * ifname, int number)
853: {
854: int i;
855: struct acl_pool *rp;
856:
857: rp=ap;
858: i=-1;
859: while (rp != NULL) {
860: if ((rp->acl_number == number) && (strncmp(rp->ifname,ifname,IFNAMSIZ) == 0)) {
861: i = rp->real_number;
862: break;
863: };
864: rp = rp->next;
865: };
866: return(i);
867: }
868:
869: /*
1.1.1.3 ! misho 870: * IfaceParseACL ()
1.1 misho 871: *
1.1.1.3 ! misho 872: * Parses ACL and replaces %r, %p and %q macroses
1.1 misho 873: * by the real numbers of rules, queues and pipes.
1.1.1.3 ! misho 874: *
! 875: * Also replaces %a1 and a2 with the remote(peer)
! 876: * or local(self) IP address respectively.
1.1 misho 877: */
878:
879: static char *
1.1.1.3 ! misho 880: IfaceParseACL (char * src, IfaceState iface)
1.1 misho 881: {
882: char *buf,*buf1;
883: char *begin,*param,*end;
884: char t;
885: int num,real_number;
886: struct acl_pool *ap;
1.1.1.3 ! misho 887: char hisaddr[20];
! 888: int ipmode = 0; /* 0 - normal macro, 1 - IP address macro */
1.1 misho 889:
1.1.1.2 misho 890: buf = Malloc(MB_IPFW, ACL_LEN);
891: buf1 = Malloc(MB_IPFW, ACL_LEN);
1.1 misho 892:
893: strlcpy(buf, src, ACL_LEN);
894: do {
895: end = buf;
896: begin = strsep(&end, "%");
897: param = strsep(&end, " ");
898: if (param != NULL) {
899: if (sscanf(param,"%c%d", &t, &num) == 2) {
900: switch (t) {
901: case 'r':
902: ap = rule_pool;
903: break;
904: case 'p':
905: ap = pipe_pool;
906: break;
907: case 'q':
908: ap = queue_pool;
909: break;
910: case 't':
911: ap = table_pool;
912: break;
1.1.1.3 ! misho 913: case 'a':
! 914: ipmode = 1;
! 915: if (num == 1)
! 916: u_addrtoa(&iface->peer_addr, hisaddr, sizeof(hisaddr));
! 917: else if (num == 2)
! 918: u_rangetoa(&iface->self_addr, hisaddr, sizeof(hisaddr));
! 919: else
! 920: ipmode = 0;
! 921: ap = NULL;
! 922: break;
1.1 misho 923: default:
924: ap = NULL;
925: };
1.1.1.3 ! misho 926: if (ipmode)
! 927: {
! 928: if (end != NULL)
! 929: snprintf(buf1, ACL_LEN, "%s%s %s", begin, hisaddr, end);
! 930: else
! 931: snprintf(buf1, ACL_LEN, "%s%s", begin, hisaddr);
! 932: ipmode = 0;
! 933: }
! 934: else
! 935: {
! 936: real_number = IfaceFindACL(ap, iface->ifname, num);
! 937: if (end != NULL)
! 938: snprintf(buf1, ACL_LEN, "%s%d %s", begin, real_number, end);
! 939: else
! 940: snprintf(buf1, ACL_LEN, "%s%d", begin, real_number);
! 941: }
1.1 misho 942: strlcpy(buf, buf1, ACL_LEN);
943: };
944: };
945: } while (end != NULL);
946: Freee(buf1);
947: return(buf);
948: }
949: #endif /* USE_IPFW */
950:
951: /*
952: * IfaceIpIfaceUp()
953: *
954: * Bring up the IP interface. The "ready" flag means that
955: * IPCP is also up and we can deliver packets immediately.
956: */
957:
958: int
959: IfaceIpIfaceUp(Bund b, int ready)
960: {
961: IfaceState const iface = &b->iface;
962: struct sockaddr_dl hwa;
963: char hisaddr[20];
964: IfaceRoute r;
965: u_char *ether;
966:
967: if (ready && !iface->conf.self_addr_force) {
968: in_addrtou_range(&b->ipcp.want_addr, 32, &iface->self_addr);
969: } else {
970: u_rangecopy(&iface->conf.self_addr, &iface->self_addr);
971: }
972: if (ready && !iface->conf.peer_addr_force) {
973: in_addrtou_addr(&b->ipcp.peer_addr, &iface->peer_addr);
974: } else {
975: u_addrcopy(&iface->conf.peer_addr, &iface->peer_addr);
976: }
977:
978: if (IfaceNgIpInit(b, ready)) {
979: Log(LG_ERR, ("[%s] IFACE: IfaceNgIpInit() error, closing IPCP", b->name));
980: FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
981: return (-1);
982: };
983:
984: /* Set addresses */
985: if (!u_rangeempty(&iface->self_addr) &&
986: IfaceChangeAddr(b, 1, &iface->self_addr, &iface->peer_addr)) {
987: Log(LG_ERR, ("[%s] IFACE: IfaceChangeAddr() error, closing IPCP", b->name));
988: FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
989: return (-1);
990: };
991:
992: /* Proxy ARP for peer if desired and peer's address is known */
993: u_addrclear(&iface->proxy_addr);
994: if (Enabled(&iface->options, IFACE_CONF_PROXY)) {
1.1.1.3 ! misho 995: u_addrtoa(&iface->peer_addr,hisaddr,sizeof(hisaddr));
1.1 misho 996: if (u_addrempty(&iface->peer_addr)) {
1.1.1.3 ! misho 997: Log(LG_IFACE, ("[%s] IFACE: Can't proxy arp for %s",
! 998: b->name, hisaddr));
1.1 misho 999: } else if (GetEther(&iface->peer_addr, &hwa) < 0) {
1.1.1.3 ! misho 1000: Log(LG_IFACE, ("[%s] IFACE: No interface to proxy arp on for %s",
! 1001: b->name, hisaddr));
1.1 misho 1002: } else {
1003: ether = (u_char *) LLADDR(&hwa);
1004: if (ExecCmdNosh(LG_IFACE2, b->name,
1005: "%s -S %s %x:%x:%x:%x:%x:%x pub",
1.1.1.3 ! misho 1006: PATH_ARP, hisaddr,
1.1 misho 1007: ether[0], ether[1], ether[2],
1008: ether[3], ether[4], ether[5]) == 0)
1.1.1.3 ! misho 1009: iface->proxy_addr = iface->peer_addr;
1.1 misho 1010: }
1011: }
1012:
1013: /* Add static routes */
1014: SLIST_FOREACH(r, &iface->routes, next) {
1015: if (u_rangefamily(&r->dest)==AF_INET) {
1016: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_addr) == 0);
1017: }
1018: }
1019: /* Add dynamic routes */
1020: SLIST_FOREACH(r, &b->params.routes, next) {
1021: if (u_rangefamily(&r->dest)==AF_INET) {
1022: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_addr) == 0);
1023: }
1024: }
1025:
1026: #ifdef USE_NG_NAT
1027: /* Set NAT IP */
1028: if (iface->nat_up)
1029: IfaceSetupNAT(b);
1030: #endif
1031:
1032: /* Call "up" script */
1033: if (*iface->up_script) {
1034: char selfbuf[40],peerbuf[40];
1035: char ns1buf[21], ns2buf[21];
1036: int res;
1037:
1038: if(b->ipcp.want_dns[0].s_addr != 0)
1039: snprintf(ns1buf, sizeof(ns1buf), "dns1 %s", inet_ntoa(b->ipcp.want_dns[0]));
1040: else
1041: ns1buf[0] = '\0';
1042: if(b->ipcp.want_dns[1].s_addr != 0)
1043: snprintf(ns2buf, sizeof(ns2buf), "dns2 %s", inet_ntoa(b->ipcp.want_dns[1]));
1044: else
1045: ns2buf[0] = '\0';
1046:
1.1.1.3 ! misho 1047: res = ExecCmd(LG_IFACE2, b->name, "%s %s inet %s %s '%s' '%s' '%s' '%s' '%s'",
! 1048: iface->up_script, iface->ifname,
! 1049: u_rangetoa(&iface->self_addr,selfbuf, sizeof(selfbuf)),
1.1 misho 1050: u_addrtoa(&iface->peer_addr, peerbuf, sizeof(peerbuf)),
1051: *b->params.authname ? b->params.authname : "-",
1.1.1.3 ! misho 1052: ns1buf, ns2buf, *b->params.peeraddr ? b->params.peeraddr : "-",
! 1053: b->params.filter_id ? b->params.filter_id : "-");
1.1 misho 1054: if (res != 0) {
1055: FsmFailure(&b->ipcp.fsm, FAIL_NEGOT_FAILURE);
1056: return (-1);
1057: }
1058: }
1059: return (0);
1060: }
1061:
1062: /*
1063: * IfaceIpIfaceDown()
1064: *
1065: * Bring down the IP interface. This implies we're no longer ready.
1066: */
1067:
1068: void
1069: IfaceIpIfaceDown(Bund b)
1070: {
1071: IfaceState const iface = &b->iface;
1072: IfaceRoute r;
1073: char buf[48];
1074:
1075: /* Call "down" script */
1076: if (*iface->down_script) {
1077: char selfbuf[40],peerbuf[40];
1078:
1.1.1.3 ! misho 1079: ExecCmd(LG_IFACE2, b->name, "%s %s inet %s %s '%s' '%s' '%s'",
! 1080: iface->down_script, iface->ifname,
! 1081: u_rangetoa(&iface->self_addr,selfbuf, sizeof(selfbuf)),
1.1 misho 1082: u_addrtoa(&iface->peer_addr, peerbuf, sizeof(peerbuf)),
1083: *b->params.authname ? b->params.authname : "-",
1.1.1.3 ! misho 1084: *b->params.peeraddr ? b->params.peeraddr : "-",
! 1085: b->params.filter_id ? b->params.filter_id : "-");
1.1 misho 1086: }
1087:
1088: /* Delete dynamic routes */
1089: SLIST_FOREACH(r, &b->params.routes, next) {
1090: if (u_rangefamily(&r->dest)==AF_INET) {
1091: if (!r->ok)
1092: continue;
1093: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_addr);
1094: r->ok = 0;
1095: }
1096: }
1097: /* Delete static routes */
1098: SLIST_FOREACH(r, &iface->routes, next) {
1099: if (u_rangefamily(&r->dest)==AF_INET) {
1100: if (!r->ok)
1101: continue;
1102: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_addr);
1103: r->ok = 0;
1104: }
1105: }
1106:
1107: /* Delete any proxy arp entry */
1108: if (!u_addrempty(&iface->proxy_addr))
1109: ExecCmdNosh(LG_IFACE2, b->name, "%s -d %s", PATH_ARP, u_addrtoa(&iface->proxy_addr, buf, sizeof(buf)));
1110: u_addrclear(&iface->proxy_addr);
1111:
1112: /* Remove address from interface */
1113: if (!u_rangeempty(&iface->self_addr))
1114: IfaceChangeAddr(b, 0, &iface->self_addr, &iface->peer_addr);
1115:
1116: IfaceNgIpShutdown(b);
1117: }
1118:
1119: /*
1120: * IfaceIpv6IfaceUp()
1121: *
1122: * Bring up the IPv6 interface. The "ready" flag means that
1123: * IPv6CP is also up and we can deliver packets immediately.
1124: */
1125:
1126: int
1127: IfaceIpv6IfaceUp(Bund b, int ready)
1128: {
1129: IfaceState const iface = &b->iface;
1130: IfaceRoute r;
1131:
1132: if (ready && !iface->conf.self_ipv6_addr_force) {
1133: iface->self_ipv6_addr.family = AF_INET6;
1134: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[0] = 0x80fe; /* Network byte order */
1135: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[1] = 0x0000;
1136: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[2] = 0x0000;
1137: iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[3] = 0x0000;
1.1.1.3 ! misho 1138: bcopy(b->ipv6cp.myintid, &iface->self_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[4], sizeof(b->ipv6cp.myintid));
! 1139: bcopy(&iface->self_ipv6_addr.u.ip6, &b->ipv6cp.want_addr, sizeof(struct in6_addr));
1.1 misho 1140: } else {
1141: u_addrcopy(&iface->conf.self_ipv6_addr, &iface->self_ipv6_addr);
1142: }
1143: if (ready && !iface->conf.peer_ipv6_addr_force) {
1144: iface->peer_ipv6_addr.family = AF_INET6;
1145: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[0] = 0x80fe; /* Network byte order */
1146: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[1] = 0x0000;
1147: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[2] = 0x0000;
1148: iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[3] = 0x0000;
1.1.1.3 ! misho 1149: bcopy(b->ipv6cp.hisintid, &iface->peer_ipv6_addr.u.ip6.__u6_addr.__u6_addr16[4], sizeof(b->ipv6cp.hisintid));
! 1150: bcopy(&iface->peer_ipv6_addr.u.ip6, &b->ipv6cp.peer_addr, sizeof(struct in6_addr));
1.1 misho 1151: } else {
1152: u_addrcopy(&iface->conf.peer_ipv6_addr, &iface->peer_ipv6_addr);
1153: }
1154:
1155: if (IfaceNgIpv6Init(b, ready)) {
1156: Log(LG_ERR, ("[%s] IFACE: IfaceNgIpv6Init() failed, closing IPv6CP", b->name));
1157: FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
1158: return (-1);
1159: };
1160:
1161: /* Set addresses */
1162: if (!u_addrempty(&iface->self_ipv6_addr)) {
1163: struct u_range rng;
1164: rng.addr = iface->self_ipv6_addr;
1165: rng.width = 64;
1166: if (IfaceChangeAddr(b, 1, &rng, &iface->peer_ipv6_addr)) {
1167: Log(LG_ERR, ("[%s] IFACE: IfaceChangeAddr() failed, closing IPv6CP", b->name));
1168: FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
1169: return (-1);
1170: }
1171: };
1172:
1173: /* Add static routes */
1174: SLIST_FOREACH(r, &iface->routes, next) {
1175: if (u_rangefamily(&r->dest)==AF_INET6) {
1176: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_ipv6_addr) == 0);
1177: }
1178: }
1179: /* Add dynamic routes */
1180: SLIST_FOREACH(r, &b->params.routes, next) {
1181: if (u_rangefamily(&r->dest)==AF_INET6) {
1182: r->ok = (IfaceSetRoute(b, RTM_ADD, &r->dest, &iface->peer_ipv6_addr) == 0);
1183: }
1184: }
1185:
1186: /* Call "up" script */
1187: if (*iface->up_script) {
1188: char selfbuf[48],peerbuf[48];
1189: int res;
1190:
1.1.1.3 ! misho 1191: res = ExecCmd(LG_IFACE2, b->name, "%s %s inet6 %s%%%s %s%%%s '%s' '%s' '%s'",
1.1 misho 1192: iface->up_script, iface->ifname,
1193: u_addrtoa(&iface->self_ipv6_addr, selfbuf, sizeof(selfbuf)), iface->ifname,
1194: u_addrtoa(&iface->peer_ipv6_addr, peerbuf, sizeof(peerbuf)), iface->ifname,
1195: *b->params.authname ? b->params.authname : "-",
1.1.1.3 ! misho 1196: *b->params.peeraddr ? b->params.peeraddr : "-",
! 1197: b->params.filter_id ? b->params.filter_id : "-");
1.1 misho 1198: if (res != 0) {
1199: FsmFailure(&b->ipv6cp.fsm, FAIL_NEGOT_FAILURE);
1200: return (-1);
1201: }
1202: }
1203: return (0);
1204:
1205: }
1206:
1207: /*
1208: * IfaceIpv6IfaceDown()
1209: *
1210: * Bring down the IPv6 interface. This implies we're no longer ready.
1211: */
1212:
1213: void
1214: IfaceIpv6IfaceDown(Bund b)
1215: {
1216: IfaceState const iface = &b->iface;
1217: IfaceRoute r;
1218: struct u_range rng;
1219:
1220: /* Call "down" script */
1221: if (*iface->down_script) {
1222: char selfbuf[48],peerbuf[48];
1223:
1.1.1.3 ! misho 1224: ExecCmd(LG_IFACE2, b->name, "%s %s inet6 %s%%%s %s%%%s '%s' '%s' '%s'",
1.1 misho 1225: iface->down_script, iface->ifname,
1226: u_addrtoa(&iface->self_ipv6_addr, selfbuf, sizeof(selfbuf)), iface->ifname,
1227: u_addrtoa(&iface->peer_ipv6_addr, peerbuf, sizeof(peerbuf)), iface->ifname,
1228: *b->params.authname ? b->params.authname : "-",
1.1.1.3 ! misho 1229: *b->params.peeraddr ? b->params.peeraddr : "-",
! 1230: b->params.filter_id ? b->params.filter_id : "-");
1.1 misho 1231: }
1232:
1233: /* Delete dynamic routes */
1234: SLIST_FOREACH(r, &b->params.routes, next) {
1235: if (u_rangefamily(&r->dest)==AF_INET6) {
1236: if (!r->ok)
1237: continue;
1238: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_ipv6_addr);
1239: r->ok = 0;
1240: }
1241: }
1242: /* Delete static routes */
1243: SLIST_FOREACH(r, &iface->routes, next) {
1244: if (u_rangefamily(&r->dest)==AF_INET6) {
1245: if (!r->ok)
1246: continue;
1247: IfaceSetRoute(b, RTM_DELETE, &r->dest, &iface->peer_ipv6_addr);
1248: r->ok = 0;
1249: }
1250: }
1251:
1252: if (!u_addrempty(&iface->self_ipv6_addr)) {
1253: /* Remove address from interface */
1254: rng.addr = iface->self_ipv6_addr;
1255: rng.width = 64;
1256: IfaceChangeAddr(b, 0, &rng, &iface->peer_ipv6_addr);
1257: }
1258:
1259: IfaceNgIpv6Shutdown(b);
1260: }
1261:
1262: /*
1263: * IfaceIdleTimeout()
1264: */
1265:
1266: static void
1267: IfaceIdleTimeout(void *arg)
1268: {
1269: Bund b = (Bund)arg;
1270:
1271: IfaceState const iface = &b->iface;
1272: int k;
1273:
1274: /* Get updated bpf node traffic statistics */
1275: BundUpdateStats(b);
1276:
1277: /* Mark current traffic period if there was traffic */
1278: if (iface->idleStats.recvFrames + iface->idleStats.xmitFrames <
1279: b->stats.recvFrames + b->stats.xmitFrames) {
1280: iface->traffic[0] = TRUE;
1281: } else { /* no demand traffic for a whole idle timeout period? */
1282: for (k = 0; k < IFACE_IDLE_SPLIT && !iface->traffic[k]; k++);
1283: if (k == IFACE_IDLE_SPLIT) {
1284: Log(LG_BUND, ("[%s] IFACE: Idle timeout", b->name));
1285: RecordLinkUpDownReason(b, NULL, 0, STR_IDLE_TIMEOUT, NULL);
1286: BundClose(b);
1287: return;
1288: }
1289: }
1290:
1291: iface->idleStats = b->stats;
1292:
1293: /* Shift traffic history */
1294: memmove(iface->traffic + 1,
1295: iface->traffic, (IFACE_IDLE_SPLIT - 1) * sizeof(*iface->traffic));
1296: iface->traffic[0] = FALSE;
1297:
1298: /* Restart timer */
1299: TimerStart(&iface->idleTimer);
1300: }
1301:
1302: /*
1303: * IfaceSessionTimeout()
1304: */
1305:
1306: static void
1307: IfaceSessionTimeout(void *arg)
1308: {
1309: Bund b = (Bund)arg;
1310:
1311: Log(LG_BUND, ("[%s] IFACE: Session timeout", b->name));
1312:
1313: RecordLinkUpDownReason(b, NULL, 0, STR_SESSION_TIMEOUT, NULL);
1314:
1315: BundClose(b);
1316:
1317: }
1318:
1319: /*
1320: * IfaceCachePkt()
1321: *
1322: * A packet caused dial-on-demand; save it for later if possible.
1323: * Consumes the mbuf in any case.
1324: */
1325:
1326: static void
1327: IfaceCachePkt(Bund b, int proto, Mbuf pkt)
1328: {
1329: IfaceState const iface = &b->iface;
1330:
1331: /* Only cache network layer data */
1332: if (!PROT_NETWORK_DATA(proto)) {
1333: mbfree(pkt);
1334: return;
1335: }
1336:
1337: /* Release previously cached packet, if any, and save this one */
1338: if (iface->dodCache.pkt)
1339: mbfree(iface->dodCache.pkt);
1340:
1341: iface->dodCache.pkt = pkt;
1342: iface->dodCache.proto = proto;
1343: iface->dodCache.ts = time(NULL);
1344: }
1345:
1346: /*
1347: * IfaceCacheSend()
1348: *
1349: * Send cached packet
1350: */
1351:
1352: static void
1353: IfaceCacheSend(Bund b)
1354: {
1355: IfaceState const iface = &b->iface;
1356:
1357: if (iface->dodCache.pkt) {
1358: if (iface->dodCache.ts + MAX_DOD_CACHE_DELAY < time(NULL))
1359: mbfree(iface->dodCache.pkt);
1360: else {
1361: if (NgFuncWritePppFrame(b, NG_PPP_BUNDLE_LINKNUM,
1362: iface->dodCache.proto, iface->dodCache.pkt) < 0) {
1363: Perror("[%s] can't write cached pkt", b->name);
1364: }
1365: }
1366: iface->dodCache.pkt = NULL;
1367: }
1368: }
1369:
1370: /*
1371: * IfaceIsDemand()
1372: *
1373: * Determine if this outgoing packet qualifies for dial-on-demand
1374: */
1375:
1376: static int
1377: IfaceIsDemand(int proto, Mbuf pkt)
1378: {
1379: switch (proto) {
1380: case PROTO_IP:
1381: {
1382: struct ip *ip;
1383:
1384: if (MBLEN(pkt) < sizeof(struct ip))
1385: return (0);
1386:
1387: ip = (struct ip *)MBDATA(pkt);
1388: switch (ip->ip_p) {
1389: case IPPROTO_IGMP: /* No multicast stuff */
1390: return(0);
1391: #if (!defined(__FreeBSD__) || __FreeBSD_version >= 600025)
1392: case IPPROTO_ICMP:
1393: {
1394: struct icmphdr *icmp;
1395:
1396: if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct icmphdr)))
1397: return (0);
1398:
1399: icmp = (struct icmphdr *) ((u_int32_t *) ip + ip->ip_hl);
1400:
1401: switch (icmp->icmp_type) /* No ICMP replies */
1402: {
1403: case ICMP_ECHOREPLY:
1404: case ICMP_UNREACH:
1405: case ICMP_REDIRECT:
1406: return(0);
1407: default:
1408: break;
1409: }
1410: }
1411: break;
1412: #endif
1413: case IPPROTO_UDP:
1414: {
1415: struct udphdr *udp;
1416:
1417: if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct udphdr)))
1418: return (0);
1419:
1420: udp = (struct udphdr *) ((u_int32_t *) ip + ip->ip_hl);
1421:
1422: #define NTP_PORT 123
1423: if (ntohs(udp->uh_dport) == NTP_PORT) /* No NTP packets */
1424: return(0);
1425: }
1426: break;
1427: case IPPROTO_TCP:
1428: {
1429: struct tcphdr *tcp;
1430:
1431: if (MBLEN(pkt) < (ip->ip_hl * 4 + sizeof(struct tcphdr)))
1432: return (0);
1433:
1434: tcp = (struct tcphdr *) ((u_int32_t *) ip + ip->ip_hl);
1435:
1436: if (tcp->th_flags & TH_RST) /* No TCP reset packets */
1437: return(0);
1438: }
1439: break;
1440: default:
1441: break;
1442: }
1443: break;
1444: }
1445: default:
1446: break;
1447: }
1448: return(1);
1449: }
1450:
1451: /*
1452: * IfaceSetCommand()
1453: */
1454:
1455: static int
1456: IfaceSetCommand(Context ctx, int ac, char *av[], void *arg)
1457: {
1458: IfaceState const iface = &ctx->bund->iface;
1459: int empty_arg;
1460:
1461: switch ((intptr_t)arg) {
1462: case SET_NAME:
1463: #ifdef SIOCSIFDESCR
1464: case SET_DESCR:
1465: #endif
1466: case SET_UP_SCRIPT:
1467: case SET_DOWN_SCRIPT:
1468: empty_arg = TRUE;
1469: break;
1470: default:
1471: empty_arg = FALSE;
1472: break;
1473: }
1474:
1475: if ((ac == 0) && (empty_arg == FALSE))
1476: return(-1);
1477: switch ((intptr_t)arg) {
1478: case SET_IDLE:
1479: iface->idle_timeout = atoi(*av);
1480: break;
1481: case SET_SESSION:
1482: iface->session_timeout = atoi(*av);
1483: break;
1484: case SET_ADDRS:
1485: {
1486: struct u_range self_addr;
1487: struct u_addr peer_addr;
1488: int self_addr_force = 0, peer_addr_force = 0;
1489: char *arg;
1490:
1491: /* Parse */
1492: if (ac != 2)
1493: return(-1);
1494: arg = av[0];
1495: if (arg[0] == '!') {
1496: self_addr_force = 1;
1497: arg++;
1498: }
1499: if (!ParseRange(arg, &self_addr, ALLOW_IPV4|ALLOW_IPV6))
1500: Error("Bad IP address \"%s\"", av[0]);
1501: arg = av[1];
1502: if (arg[0] == '!') {
1503: peer_addr_force = 1;
1504: arg++;
1505: }
1506: if (!ParseAddr(arg, &peer_addr, ALLOW_IPV4|ALLOW_IPV6))
1507: Error("Bad IP address \"%s\"", av[1]);
1508: if (self_addr.addr.family != peer_addr.family)
1509: Error("Addresses must be from the same protocol family");
1510:
1511: /* OK */
1512: if (peer_addr.family == AF_INET) {
1513: iface->conf.self_addr = self_addr;
1514: iface->conf.peer_addr = peer_addr;
1515: iface->conf.self_addr_force = self_addr_force;
1516: iface->conf.peer_addr_force = peer_addr_force;
1517: } else {
1518: iface->conf.self_ipv6_addr = self_addr.addr;
1519: iface->conf.peer_ipv6_addr = peer_addr;
1520: iface->conf.self_ipv6_addr_force = self_addr_force;
1521: iface->conf.peer_ipv6_addr_force = peer_addr_force;
1522: }
1523: }
1524: break;
1525:
1526: case SET_ROUTE:
1527: {
1528: struct u_range range;
1529: IfaceRoute r;
1530:
1531: /* Check */
1532: if (ac != 1)
1533: return(-1);
1534:
1535: /* Get dest address */
1536: if (!strcasecmp(av[0], "default")) {
1537: u_rangeclear(&range);
1538: range.addr.family=AF_INET;
1539: }
1540: else if (!ParseRange(av[0], &range, ALLOW_IPV4|ALLOW_IPV6))
1541: Error("Bad route dest address \"%s\"", av[0]);
1542: r = Malloc(MB_IFACE, sizeof(struct ifaceroute));
1543: r->dest = range;
1544: r->ok = 0;
1545: SLIST_INSERT_HEAD(&iface->routes, r, next);
1546: }
1547: break;
1548:
1549: case SET_MTU:
1550: {
1551: int max_mtu;
1552:
1553: /* Check */
1554: if (ac != 1)
1555: return(-1);
1556:
1557: max_mtu = atoi(av[0]);
1558: if (max_mtu < IFACE_MIN_MTU || max_mtu > IFACE_MAX_MTU)
1559: Error("Invalid interface mtu %d", max_mtu);
1560: iface->max_mtu = max_mtu;
1561: }
1562: break;
1563:
1564: case SET_NAME:
1565: switch (ac) {
1566: case 0:
1567: /* Restore original interface name */
1568: if (strcmp(iface->ifname, iface->ngname) != 0) {
1569: iface->conf.ifname[0] = '\0';
1570: return IfaceSetName(ctx->bund, iface->ngname);
1571: }
1572: break;
1573: case 1:
1574: if (strcmp(iface->ifname, av[0]) != 0) {
1575: int ifmaxlen = IF_NAMESIZE - ctx->bund->tmpl * IFNUMLEN;
1576: if (strlen(av[0]) >= ifmaxlen)
1577: Error("Interface name too long, >%d characters", ifmaxlen-1);
1578: if ((strncmp(av[0], "ng", 2) == 0) &&
1579: ((ctx->bund->tmpl && av[0][2] == 0) ||
1580: (av[0][2] >= '0' && av[0][2] <= '9')))
1581: Error("This interface name is reserved");
1582: strlcpy(iface->conf.ifname, av[0], sizeof(iface->conf.ifname));
1583: return IfaceSetName(ctx->bund, av[0]);
1584: }
1585: break;
1586: default:
1587: return(-1);
1588: }
1589: break;
1590: #ifdef SIOCSIFDESCR
1591: case SET_DESCR:
1.1.1.2 misho 1592: IfaceFreeDescr(iface);
1.1 misho 1593: switch (ac) {
1594: case 0:
1595: return IfaceSetDescr(ctx->bund, "");
1596: break;
1597: case 1:
1598: iface->conf.ifdescr = Mstrdup(MB_IFACE, av[0]);
1.1.1.2 misho 1599: return IfaceSetDescr(ctx->bund, av[0]);
1.1 misho 1600: break;
1601: default:
1602: return(-1);
1603: }
1604: break;
1605: #endif
1606: #ifdef SIOCAIFGROUP
1607: case SET_GROUP:
1608: if (ac != 1)
1609: return(-1);
1610:
1611: if (av[0][0] && isdigit(av[0][strlen(av[0]) - 1]))
1612: Error("Groupnames may not end in a digit");
1613: if (strlen(av[0]) >= IFNAMSIZ)
1614: Error("Group name %s too long", av[0]);
1615: if (iface->conf.ifgroup[0] != 0)
1616: IfaceDelGroup(ctx->bund, iface->conf.ifgroup);
1617: strlcpy(iface->conf.ifgroup, av[0], IFNAMSIZ);
1618: return IfaceAddGroup(ctx->bund, av[0]);
1619: break;
1620: #endif
1621: case SET_UP_SCRIPT:
1622: switch (ac) {
1623: case 0:
1624: *iface->up_script = 0;
1625: break;
1626: case 1:
1627: strlcpy(iface->up_script, av[0], sizeof(iface->up_script));
1628: break;
1629: default:
1630: return(-1);
1631: }
1632: break;
1633:
1634: case SET_DOWN_SCRIPT:
1635: switch (ac) {
1636: case 0:
1637: *iface->down_script = 0;
1638: break;
1639: case 1:
1640: strlcpy(iface->down_script, av[0], sizeof(iface->down_script));
1641: break;
1642: default:
1643: return(-1);
1644: }
1645: break;
1646:
1647: case SET_ENABLE:
1648: EnableCommand(ac, av, &iface->options, gConfList);
1649: break;
1650:
1651: case SET_DISABLE:
1652: DisableCommand(ac, av, &iface->options, gConfList);
1653: break;
1654:
1655: default:
1656: assert(0);
1657: }
1658: return(0);
1659: }
1660:
1661: /*
1662: * IfaceStat()
1663: */
1664:
1665: int
1666: IfaceStat(Context ctx, int ac, char *av[], void *arg)
1667: {
1668: Bund const b = ctx->bund;
1669: IfaceState const iface = &b->iface;
1670: IfaceRoute r;
1671: #ifdef USE_NG_BPF
1672: int k;
1673: #endif
1674: char buf[48];
1675: #if defined(USE_NG_BPF) || defined(USE_IPFW)
1676: struct acl *a;
1677: #endif
1678:
1679: Printf("Interface configuration:\r\n");
1680: Printf("\tName : %s\r\n", iface->conf.ifname);
1681: #ifdef SIOCSIFDESCR
1682: Printf("\tDescription : \"%s\"\r\n",
1.1.1.2 misho 1683: (iface->ifdescr != NULL) ? iface->ifdescr : "<none>");
1.1 misho 1684: #endif
1685: #ifdef SIOCAIFGROUP
1686: Printf("\tGroup : %s\r\n", iface->conf.ifgroup);
1687: #endif
1688: Printf("\tMaximum MTU : %d bytes\r\n", iface->max_mtu);
1689: Printf("\tIdle timeout : %d seconds\r\n", iface->idle_timeout);
1690: Printf("\tSession timeout : %d seconds\r\n", iface->session_timeout);
1691: if (!u_rangeempty(&iface->conf.self_addr)) {
1692: Printf("\tIP Addresses : %s%s -> ", iface->conf.self_addr_force?"!":"",
1693: u_rangetoa(&iface->conf.self_addr,buf,sizeof(buf)));
1694: Printf("%s%s\r\n", iface->conf.peer_addr_force?"!":"",
1695: u_addrtoa(&iface->conf.peer_addr,buf,sizeof(buf)));
1696: }
1697: if (!u_addrempty(&iface->conf.self_ipv6_addr)) {
1698: Printf("\tIPv6 Addresses : %s%s%%%s -> ", iface->conf.self_ipv6_addr_force?"!":"",
1699: u_addrtoa(&iface->conf.self_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1700: Printf("%s%s%%%s\r\n", iface->conf.peer_ipv6_addr_force?"!":"",
1701: u_addrtoa(&iface->conf.peer_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1702: }
1703: Printf("\tEvent scripts\r\n");
1704: Printf("\t up-script : \"%s\"\r\n",
1705: *iface->up_script ? iface->up_script : "<none>");
1706: Printf("\t down-script : \"%s\"\r\n",
1707: *iface->down_script ? iface->down_script : "<none>");
1708: Printf("Interface options:\r\n");
1709: OptStat(ctx, &iface->options, gConfList);
1710: if (!SLIST_EMPTY(&iface->routes)) {
1711: Printf("Static routes via peer:\r\n");
1712: SLIST_FOREACH(r, &iface->routes, next) {
1713: Printf("\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
1714: }
1715: }
1716: Printf("Interface status:\r\n");
1717: Printf("\tAdmin status : %s\r\n", iface->open ? "OPEN" : "CLOSED");
1718: Printf("\tStatus : %s\r\n", iface->up ? (iface->dod?"DoD":"UP") : "DOWN");
1719: Printf("\tName : %s\r\n", iface->ifname);
1720: #ifdef SIOCSIFDESCR
1721: Printf("\tDescription : \"%s\"\r\n",
1722: (iface->ifdescr != NULL) ? iface->ifdescr : "<none>");
1723: #endif
1724: if (iface->up) {
1725: Printf("\tSession time : %ld seconds\r\n", (long int)(time(NULL) - iface->last_up));
1726: if (b->params.idle_timeout || iface->idle_timeout)
1727: Printf("\tIdle timeout : %d seconds\r\n", b->params.idle_timeout?b->params.idle_timeout:iface->idle_timeout);
1728: if (b->params.session_timeout || iface->session_timeout)
1729: Printf("\tSession timeout : %d seconds\r\n", b->params.session_timeout?b->params.session_timeout:iface->session_timeout);
1730: Printf("\tMTU : %d bytes\r\n", iface->mtu);
1731: }
1732: if (iface->ip_up && !u_rangeempty(&iface->self_addr)) {
1733: Printf("\tIP Addresses : %s -> ", u_rangetoa(&iface->self_addr,buf,sizeof(buf)));
1734: Printf("%s\r\n", u_addrtoa(&iface->peer_addr,buf,sizeof(buf)));
1735: }
1736: if (iface->ipv6_up && !u_addrempty(&iface->self_ipv6_addr)) {
1737: Printf("\tIPv6 Addresses : %s%%%s -> ",
1738: u_addrtoa(&iface->self_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1739: Printf("%s%%%s\r\n", u_addrtoa(&iface->peer_ipv6_addr,buf,sizeof(buf)), iface->ifname);
1740: }
1741: if (iface->up) {
1742: Printf("Dynamic routes via peer:\r\n");
1743: SLIST_FOREACH(r, &ctx->bund->params.routes, next) {
1744: Printf("\t%s\r\n", u_rangetoa(&r->dest,buf,sizeof(buf)));
1745: }
1746: #ifdef USE_IPFW
1747: Printf("IPFW pipes:\r\n");
1748: a = ctx->bund->params.acl_pipe;
1749: while (a) {
1750: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1751: a = a->next;
1752: }
1753: Printf("IPFW queues:\r\n");
1754: a = ctx->bund->params.acl_queue;
1755: while (a) {
1756: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1757: a = a->next;
1758: }
1759: Printf("IPFW tables:\r\n");
1760: a = ctx->bund->params.acl_table;
1761: while (a) {
1762: if (a->number != 0)
1763: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1764: else
1765: Printf("\t(%d)\t: '%s'\r\n", a->real_number, a->rule);
1766: a = a->next;
1767: }
1768: Printf("IPFW rules:\r\n");
1769: a = ctx->bund->params.acl_rule;
1770: while (a) {
1771: Printf("\t%d (%d)\t: '%s'\r\n", a->number, a->real_number, a->rule);
1772: a = a->next;
1773: }
1774: #endif /* USE_IPFW */
1775: #ifdef USE_NG_BPF
1776: Printf("Traffic filters:\r\n");
1777: for (k = 0; k < ACL_FILTERS; k++) {
1778: a = ctx->bund->params.acl_filters[k];
1779: if (a == NULL)
1780: a = acl_filters[k];
1781: while (a) {
1782: Printf("\t%d#%d\t: '%s'\r\n", (k + 1), a->number, a->rule);
1783: a = a->next;
1784: }
1785: }
1786: Printf("Traffic limits:\r\n");
1787: for (k = 0; k < 2; k++) {
1788: a = ctx->bund->params.acl_limits[k];
1789: while (a) {
1790: Printf("\t%s#%d%s%s\t: '%s'\r\n", (k?"out":"in"), a->number,
1791: ((a->name[0])?"#":""), a->name, a->rule);
1792: a = a->next;
1793: }
1794: }
1795: #endif /* USE_NG_BPF */
1796: }
1797: return(0);
1798: }
1799:
1800: /*
1801: * IfaceSetMTU()
1802: *
1803: * Set MTU and bandwidth on bundle's interface
1804: */
1805:
1806: void
1807: IfaceSetMTU(Bund b, int mtu)
1808: {
1809: IfaceState const iface = &b->iface;
1810: struct ifreq ifr;
1811: int s;
1812:
1813: /* Get socket */
1814: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1815: Perror("[%s] IFACE: Can't get socket to set MTU", b->name);
1816: return;
1817: }
1818:
1819: if ((b->params.mtu > 0) && (mtu > b->params.mtu)) {
1820: mtu = b->params.mtu;
1821: Log(LG_IFACE2, ("[%s] IFACE: forcing MTU of auth backend: %d bytes",
1822: b->name, mtu));
1823: }
1824:
1825: /* Limit MTU to configured maximum */
1826: if (mtu > iface->max_mtu)
1827: mtu = iface->max_mtu;
1828:
1829: /* Set MTU on interface */
1830: memset(&ifr, 0, sizeof(ifr));
1831: strlcpy(ifr.ifr_name, b->iface.ifname, sizeof(ifr.ifr_name));
1832: ifr.ifr_mtu = mtu;
1833: Log(LG_IFACE2, ("[%s] IFACE: setting %s MTU to %d bytes",
1834: b->name, b->iface.ifname, mtu));
1835: if (ioctl(s, SIOCSIFMTU, (char *)&ifr) < 0)
1836: Perror("[%s] IFACE: ioctl(%s, %s)", b->name, b->iface.ifname, "SIOCSIFMTU");
1837: close(s);
1838:
1839: /* Save MTU */
1840: iface->mtu = mtu;
1841:
1842: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
1843: /* Update tcpmssfix config */
1844: if (iface->mss_up)
1845: IfaceSetupMSS(b, MAXMSS(mtu));
1846: #endif
1847:
1848: }
1849:
1850: void
1851: IfaceChangeFlags(Bund b, int clear, int set)
1852: {
1853: struct ifreq ifrq;
1854: int s, new_flags;
1855:
1.1.1.2 misho 1856: Log(LG_IFACE2, ("[%s] IFACE: Change interface %s flags: -%d +%d",
1857: b->name, b->iface.ifname, clear, set));
1.1 misho 1858:
1859: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1860: Perror("[%s] IFACE: Can't get socket to change interface flags", b->name);
1861: return;
1862: }
1863:
1864: memset(&ifrq, '\0', sizeof(ifrq));
1865: strlcpy(ifrq.ifr_name, b->iface.ifname, sizeof(ifrq.ifr_name));
1866: if (ioctl(s, SIOCGIFFLAGS, &ifrq) < 0) {
1.1.1.2 misho 1867: Perror("[%s] IFACE: ioctl(SIOCGIFFLAGS, %s)", b->name, b->iface.ifname);
1.1 misho 1868: close(s);
1869: return;
1870: }
1871: new_flags = (ifrq.ifr_flags & 0xffff) | (ifrq.ifr_flagshigh << 16);
1872:
1873: new_flags &= ~clear;
1874: new_flags |= set;
1875:
1876: ifrq.ifr_flags = new_flags & 0xffff;
1877: ifrq.ifr_flagshigh = new_flags >> 16;
1878:
1879: if (ioctl(s, SIOCSIFFLAGS, &ifrq) < 0) {
1.1.1.2 misho 1880: Perror("[%s] IFACE: ioctl(SIOCSIFFLAGS, %s)", b->name, b->iface.ifname);
1.1 misho 1881: close(s);
1882: return;
1883: }
1884: close(s);
1885: }
1886:
1887: #if defined(__KAME__) && !defined(NOINET6)
1888: static void
1889: add_scope(struct sockaddr *sa, int ifindex)
1890: {
1891: struct sockaddr_in6 *sa6;
1892:
1893: if (sa->sa_family != AF_INET6)
1894: return;
1895: sa6 = (struct sockaddr_in6 *)sa;
1896: if (!IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr) &&
1897: !IN6_IS_ADDR_MC_LINKLOCAL(&sa6->sin6_addr))
1898: return;
1.1.1.3 ! misho 1899: if (sa6->sin6_addr.__u6_addr.__u6_addr16[1] != 0)
1.1 misho 1900: return;
1.1.1.3 ! misho 1901: sa6->sin6_addr.__u6_addr.__u6_addr16[1] = htons(ifindex);
1.1 misho 1902: }
1903: #endif
1904:
1905: int
1906: IfaceChangeAddr(Bund b, int add, struct u_range *self, struct u_addr *peer)
1907: {
1908: struct ifaliasreq ifra;
1909: struct in6_aliasreq ifra6;
1910: struct sockaddr_in *me4, *msk4, *peer4;
1911: struct sockaddr_storage ssself, sspeer, ssmsk;
1912: int res = 0;
1913: int s;
1914: char buf[48], buf1[48];
1915:
1916: Log(LG_IFACE2, ("[%s] IFACE: %s address %s->%s %s %s",
1917: b->name, add?"Add":"Remove", u_rangetoa(self, buf, sizeof(buf)),
1918: ((peer != NULL)?u_addrtoa(peer, buf1, sizeof(buf1)):""),
1919: add?"to":"from", b->iface.ifname));
1920:
1921: u_rangetosockaddrs(self, &ssself, &ssmsk);
1922: if (peer)
1923: u_addrtosockaddr(peer, 0, &sspeer);
1924:
1925: if ((s = socket(self->addr.family, SOCK_DGRAM, 0)) < 0) {
1926: Perror("[%s] IFACE: Can't get socket to change interface address", b->name);
1927: return (s);
1928: }
1929:
1930: switch (self->addr.family) {
1931: case AF_INET:
1932: memset(&ifra, '\0', sizeof(ifra));
1933: strlcpy(ifra.ifra_name, b->iface.ifname, sizeof(ifra.ifra_name));
1934:
1935: me4 = (struct sockaddr_in *)&ifra.ifra_addr;
1936: memcpy(me4, &ssself, sizeof(*me4));
1937:
1938: msk4 = (struct sockaddr_in *)&ifra.ifra_mask;
1939: memcpy(msk4, &ssmsk, sizeof(*msk4));
1940:
1941: peer4 = (struct sockaddr_in *)&ifra.ifra_broadaddr;
1942: if (peer == NULL || peer->family == AF_UNSPEC) {
1943: peer4->sin_family = AF_INET;
1944: peer4->sin_len = sizeof(*peer4);
1945: peer4->sin_addr.s_addr = INADDR_NONE;
1946: } else
1947: memcpy(peer4, &sspeer, sizeof(*peer4));
1948:
1949: res = ioctl(s, add?SIOCAIFADDR:SIOCDIFADDR, &ifra);
1950: if (res == -1) {
1951: Perror("[%s] IFACE: %s IPv4 address %s %s failed",
1952: b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname);
1953: }
1954: break;
1955:
1956: case AF_INET6:
1957: memset(&ifra6, '\0', sizeof(ifra6));
1958: strlcpy(ifra6.ifra_name, b->iface.ifname, sizeof(ifra6.ifra_name));
1959:
1960: memcpy(&ifra6.ifra_addr, &ssself, sizeof(ifra6.ifra_addr));
1961: memcpy(&ifra6.ifra_prefixmask, &ssmsk, sizeof(ifra6.ifra_prefixmask));
1962: if (peer == NULL || peer->family == AF_UNSPEC)
1963: ifra6.ifra_dstaddr.sin6_family = AF_UNSPEC;
1964: else if (memcmp(&((struct sockaddr_in6 *)&ssmsk)->sin6_addr, &in6mask128,
1965: sizeof(in6mask128)) == 0)
1966: memcpy(&ifra6.ifra_dstaddr, &sspeer, sizeof(ifra6.ifra_dstaddr));
1967: ifra6.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
1968: ifra6.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
1969:
1970: res = ioctl(s, add?SIOCAIFADDR_IN6:SIOCDIFADDR_IN6, &ifra6);
1971: if (res == -1) {
1.1.1.2 misho 1972: if (add && errno == EEXIST) {
1973: /* this can happen if the kernel has already automatically added
1974: the same link-local address - ignore the error */
1975: res = 0;
1976: } else {
1977: Perror("[%s] IFACE: %s IPv6 address %s %s failed",
1978: b->name, add?"Adding":"Removing", add?"to":"from", b->iface.ifname);
1979: }
1.1 misho 1980: }
1981: break;
1982:
1983: default:
1984: res = -1;
1985: break;
1986: }
1987: close(s);
1988: return (res);
1989: }
1990:
1991: struct rtmsg {
1992: struct rt_msghdr m_rtm;
1993: char m_space[256];
1994: };
1995:
1996: static size_t
1997: memcpy_roundup(char *cp, const void *data, size_t len)
1998: {
1999: size_t padlen;
2000:
2001: #define ROUNDUP(x) ((x) ? (1 + (((x) - 1) | (sizeof(long) - 1))) : sizeof(long))
2002: padlen = ROUNDUP(len);
2003: memcpy(cp, data, len);
2004: if (padlen > len)
2005: memset(cp + len, '\0', padlen - len);
2006:
2007: return padlen;
2008: }
2009:
2010: int
2011: IfaceSetRoute(Bund b, int cmd, struct u_range *dst,
2012: struct u_addr *gw)
2013: {
2014: struct rtmsg rtmes;
2015: int s, nb, wb;
2016: char *cp;
2017: const char *cmdstr = (cmd == RTM_ADD ? "Add" : "Delete");
2018: struct sockaddr_storage sadst, samask, sagw;
2019: char buf[48], buf1[48];
2020:
2021: s = socket(PF_ROUTE, SOCK_RAW, 0);
2022: if (s < 0) {
2023: Perror("[%s] IFACE: Can't get route socket", b->name);
2024: return (-1);
2025: }
2026: memset(&rtmes, '\0', sizeof(rtmes));
2027: rtmes.m_rtm.rtm_version = RTM_VERSION;
2028: rtmes.m_rtm.rtm_type = cmd;
2029: rtmes.m_rtm.rtm_addrs = RTA_DST;
2030: rtmes.m_rtm.rtm_seq = ++gRouteSeq;
2031: rtmes.m_rtm.rtm_pid = gPid;
2032: rtmes.m_rtm.rtm_flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
2033:
2034: u_rangetosockaddrs(dst, &sadst, &samask);
2035: #if defined(__KAME__) && !defined(NOINET6)
2036: add_scope((struct sockaddr *)&sadst, b->iface.ifindex);
2037: #endif
2038:
2039: cp = rtmes.m_space;
2040: cp += memcpy_roundup(cp, &sadst, sadst.ss_len);
2041: if (gw != NULL) {
2042: u_addrtosockaddr(gw, 0, &sagw);
2043: #if defined(__KAME__) && !defined(NOINET6)
2044: add_scope((struct sockaddr *)&sagw, b->iface.ifindex);
2045: #endif
2046: cp += memcpy_roundup(cp, &sagw, sagw.ss_len);
2047: rtmes.m_rtm.rtm_addrs |= RTA_GATEWAY;
2048: } else if (cmd == RTM_ADD) {
2049: Log(LG_ERR, ("[%s] IfaceSetRoute: gw is not set\n", b->name));
2050: close(s);
2051: return (-1);
2052: }
2053:
2054: if (u_rangehost(dst)) {
2055: rtmes.m_rtm.rtm_flags |= RTF_HOST;
2056: } else {
2057: cp += memcpy_roundup(cp, &samask, samask.ss_len);
2058: rtmes.m_rtm.rtm_addrs |= RTA_NETMASK;
2059: }
2060:
2061: nb = cp - (char *)&rtmes;
2062: rtmes.m_rtm.rtm_msglen = nb;
2063: wb = write(s, &rtmes, nb);
2064: if (wb < 0) {
2065: Log(LG_ERR, ("[%s] IFACE: %s route %s %s failed: %s",
2066: b->name, cmdstr, u_rangetoa(dst, buf, sizeof(buf)),
2067: ((gw != NULL)?u_addrtoa(gw, buf1, sizeof(buf1)):""),
2068: (rtmes.m_rtm.rtm_errno != 0)?strerror(rtmes.m_rtm.rtm_errno):strerror(errno)));
2069: close(s);
2070: return (-1);
2071: }
2072: close(s);
2073: Log(LG_IFACE2, ("[%s] IFACE: %s route %s %s",
2074: b->name, cmdstr, u_rangetoa(dst, buf, sizeof(buf)),
2075: ((gw != NULL)?u_addrtoa(gw, buf1, sizeof(buf1)):"")));
2076: return (0);
2077: }
2078:
2079: #ifndef USE_NG_TCPMSS
2080: void
2081: IfaceCorrectMSS(Mbuf pkt, uint16_t maxmss)
2082: {
2083: struct ip *iphdr;
2084: struct tcphdr *tc;
2085: int pktlen, hlen, olen, optlen, accumulate;
2086: uint16_t *mss;
2087: u_char *opt;
2088:
2089: if (pkt == NULL)
2090: return;
2091:
2092: iphdr = (struct ip *)MBDATAU(pkt);
2093: hlen = iphdr->ip_hl << 2;
2094: pktlen = MBLEN(pkt) - hlen;
2095: tc = (struct tcphdr *)(MBDATAU(pkt) + hlen);
2096: hlen = tc->th_off << 2;
2097:
2098: /* Invalid header length or header without options. */
2099: if (hlen <= sizeof(struct tcphdr) || hlen > pktlen)
2100: return;
2101:
2102: /* MSS option only allowed within SYN packets. */
2103: if (!(tc->th_flags & TH_SYN))
2104: return;
2105:
2106: for (olen = hlen - sizeof(struct tcphdr), opt = (u_char *)(tc + 1);
2107: olen > 0; olen -= optlen, opt += optlen) {
2108: if (*opt == TCPOPT_EOL)
2109: break;
2110: else if (*opt == TCPOPT_NOP)
2111: optlen = 1;
2112: else {
2113: optlen = *(opt + 1);
2114: if (optlen <= 0 || optlen > olen)
2115: break;
2116: if (*opt == TCPOPT_MAXSEG) {
2117: if (optlen != TCPOLEN_MAXSEG)
2118: continue;
2119: mss = (u_int16_t *)(opt + 2);
2120: if (ntohs(*mss) > maxmss) {
2121: accumulate = *mss;
2122: *mss = htons(maxmss);
2123: accumulate -= *mss;
2124: ADJUST_CHECKSUM(accumulate, tc->th_sum);
2125: }
2126: }
2127: }
2128: }
2129: }
2130: #endif
2131:
2132: static int
2133: IfaceNgIpInit(Bund b, int ready)
2134: {
2135: struct ngm_connect cn;
2136: char path[NG_PATHSIZ];
2137: char hook[NG_HOOKSIZ];
2138:
2139: if (!ready) {
2140: /* Dial-on-Demand mode */
2141: /* Use demand hook of the socket node */
2142: snprintf(path, sizeof(path), ".:");
2143: snprintf(hook, sizeof(hook), "4%d", b->id);
2144:
2145: } else {
2146: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2147: strcpy(hook, NG_PPP_HOOK_INET);
2148:
2149: #ifdef USE_NG_NAT
2150: /* Add a nat node if configured */
2151: if (Enabled(&b->iface.options, IFACE_CONF_NAT)) {
2152: if (IfaceInitNAT(b, path, hook))
2153: goto fail;
2154: b->iface.nat_up = 1;
2155: }
2156: #endif
2157:
2158: /* Add a tee node if configured */
2159: if (Enabled(&b->iface.options, IFACE_CONF_TEE)) {
2160: if (IfaceInitTee(b, path, hook, 0))
2161: goto fail;
2162: b->iface.tee_up = 1;
2163: }
2164:
2165: #ifdef USE_NG_IPACCT
2166: /* Connect a ipacct node if configured */
2167: if (Enabled(&b->iface.options, IFACE_CONF_IPACCT)) {
2168: if (IfaceInitIpacct(b, path, hook))
2169: goto fail;
2170: b->iface.ipacct_up = 1;
2171: }
2172: #endif /* USE_NG_IPACCT */
2173:
2174: #ifdef USE_NG_NETFLOW
2175: #ifdef NG_NETFLOW_CONF_INGRESS
2176: /* Connect a netflow node if configured */
2177: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN) ||
2178: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
2179: if (IfaceInitNetflow(b, path, hook,
2180: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0,
1.1.1.2 misho 2181: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0, 0))
1.1 misho 2182: goto fail;
2183: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN))
2184: b->iface.nfin_up = 1;
2185: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT))
2186: b->iface.nfout_up = 1;
2187: }
2188: #else /* NG_NETFLOW_CONF_INGRESS */
2189: /* Connect a netflow node if configured */
2190: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) {
1.1.1.2 misho 2191: if (IfaceInitNetflow(b, path, hook, 1, 0, 0))
1.1 misho 2192: goto fail;
2193: b->iface.nfin_up = 1;
2194: }
2195:
2196: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
1.1.1.2 misho 2197: if (IfaceInitNetflow(b, path, hook, 0, 1, 0))
1.1 misho 2198: goto fail;
2199: b->iface.nfout_up = 1;
2200: }
2201: #endif /* NG_NETFLOW_CONF_INGRESS */
2202: #endif /* USE_NG_NETFLOW */
2203:
2204: }
2205:
2206: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2207: if (Enabled(&b->iface.options, IFACE_CONF_TCPMSSFIX)) {
2208: if (IfaceInitMSS(b, path, hook))
2209: goto fail;
2210: b->iface.mss_up = 1;
2211: }
2212: #endif
2213:
2214: #ifdef USE_NG_BPF
2215: if (IfaceInitLimits(b, path, hook))
2216: goto fail;
2217: #endif
2218:
2219: /* Connect graph to the iface node. */
2220: memset(&cn, 0, sizeof(cn));
2221: strcpy(cn.ourhook, hook);
2222: snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ngname);
2223: strcpy(cn.peerhook, NG_IFACE_HOOK_INET);
2224: if (NgSendMsg(gLinksCsock, path,
2225: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
2226: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2227: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2228: goto fail;
2229: }
2230:
2231: if (ready) {
2232: #ifdef USE_NG_NETFLOW
2233: #ifdef NG_NETFLOW_CONF_INGRESS
2234: if (b->iface.nfin_up || b->iface.nfout_up)
1.1.1.3 ! misho 2235: IfaceSetupNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 0);
1.1 misho 2236: #else /* NG_NETFLOW_CONF_INGRESS */
2237: if (b->iface.nfin_up)
1.1.1.3 ! misho 2238: IfaceSetupNetflow(b, 1, 0, 0);
1.1 misho 2239:
2240: if (b->iface.nfout_up)
1.1.1.3 ! misho 2241: IfaceSetupNetflow(b, 0, 1, 0);
1.1 misho 2242: #endif /* NG_NETFLOW_CONF_INGRESS */
2243: #endif /* USE_NG_NETFLOW */
2244: }
2245:
2246: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2247: if (b->iface.mss_up)
2248: IfaceSetupMSS(b, MAXMSS(b->iface.mtu));
2249: #endif
2250:
2251: #ifdef USE_NG_BPF
2252: IfaceSetupLimits(b);
2253: #endif
2254:
2255: /* OK */
2256: return(0);
2257:
2258: fail:
2259: return(-1);
2260: }
2261:
2262: /*
2263: * IfaceNgIpShutdown()
2264: */
2265:
2266: static void
2267: IfaceNgIpShutdown(Bund b)
2268: {
2269: char path[NG_PATHSIZ];
2270:
2271: #ifdef USE_NG_BPF
2272: IfaceShutdownLimits(b); /* Limits must shutdown first to save final stats. */
2273: #endif
2274: #ifdef USE_NG_NAT
2275: if (b->iface.nat_up)
2276: IfaceShutdownNAT(b);
2277: b->iface.nat_up = 0;
2278: #endif
2279: if (b->iface.tee_up)
2280: IfaceShutdownTee(b, 0);
2281: b->iface.tee_up = 0;
2282: #ifdef USE_NG_NETFLOW
2283: #ifdef NG_NETFLOW_CONF_INGRESS
2284: if (b->iface.nfin_up || b->iface.nfout_up)
1.1.1.3 ! misho 2285: IfaceShutdownNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 0);
1.1 misho 2286: b->iface.nfin_up = 0;
2287: b->iface.nfout_up = 0;
2288: #else /* NG_NETFLOW_CONF_INGRESS */
2289: if (b->iface.nfin_up)
1.1.1.3 ! misho 2290: IfaceShutdownNetflow(b, 1, 0, 0);
1.1 misho 2291: b->iface.nfin_up = 0;
2292: if (b->iface.nfout_up)
1.1.1.3 ! misho 2293: IfaceShutdownNetflow(b, 0, 1, 0);
1.1 misho 2294: b->iface.nfout_up = 0;
2295: #endif /* NG_NETFLOW_CONF_INGRESS */
2296: #endif
2297: #ifdef USE_NG_IPACCT
2298: if (b->iface.ipacct_up)
2299: IfaceShutdownIpacct(b);
2300: b->iface.ipacct_up = 0;
2301: #endif
2302: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2303: if (b->iface.mss_up)
2304: IfaceShutdownMSS(b);
2305: #endif
2306: b->iface.mss_up = 0;
2307:
2308: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2309: NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_INET);
2310:
2311: snprintf(path, sizeof(path), "%s:", b->iface.ngname);
2312: NgFuncDisconnect(gLinksCsock, b->name, path, NG_IFACE_HOOK_INET);
2313: }
2314:
2315: static int
2316: IfaceNgIpv6Init(Bund b, int ready)
2317: {
2318: struct ngm_connect cn;
2319: char path[NG_PATHSIZ];
2320: char hook[NG_HOOKSIZ];
2321:
2322: if (!ready) {
2323: /* Dial-on-Demand mode */
2324: /* Use demand hook of the socket node */
2325: snprintf(path, sizeof(path), ".:");
2326: snprintf(hook, sizeof(hook), "6%d", b->id);
2327: } else {
2328: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2329: strcpy(hook, NG_PPP_HOOK_IPV6);
2330:
2331: /* Add a tee node if configured */
2332: if (Enabled(&b->iface.options, IFACE_CONF_TEE)) {
2333: if (IfaceInitTee(b, path, hook, 1))
2334: goto fail;
2335: b->iface.tee6_up = 1;
2336: }
2337:
1.1.1.2 misho 2338: #ifdef USE_NG_NETFLOW
2339: #ifdef NG_NETFLOW_CONF_INGRESS
2340: /* Connect a netflow node if configured */
2341: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN) ||
2342: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
2343: if (IfaceInitNetflow(b, path, hook,
2344: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)?1:0,
2345: Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)?1:0, 1))
2346: goto fail;
2347: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN))
2348: b->iface.nfin_up = 1;
2349: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT))
2350: b->iface.nfout_up = 1;
2351: }
2352: #else /* NG_NETFLOW_CONF_INGRESS */
2353: /* Connect a netflow node if configured */
1.1.1.3 ! misho 2354: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_IN)) {
! 2355: if (IfaceInitNetflow(b, path, hook, 1, 0, 1))
1.1.1.2 misho 2356: goto fail;
2357: b->iface.nfin_up = 1;
2358: }
2359:
2360: if (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_OUT)) {
2361: if (IfaceInitNetflow(b, path, hook, 0, 1, 1))
2362: goto fail;
2363: b->iface.nfout_up = 1;
2364: }
2365: #endif /* NG_NETFLOW_CONF_INGRESS */
2366: #endif /* USE_NG_NETFLOW */
1.1 misho 2367: }
2368:
1.1.1.3 ! misho 2369: #ifdef USE_NG_BPF
! 2370: if (IfaceInitLimits(b, path, hook))
! 2371: goto fail;
! 2372: #endif
! 2373:
1.1 misho 2374: /* Connect graph to the iface node. */
2375: strcpy(cn.ourhook, hook);
2376: snprintf(cn.path, sizeof(cn.path), "%s:", b->iface.ngname);
2377: strcpy(cn.peerhook, NG_IFACE_HOOK_INET6);
2378: if (NgSendMsg(gLinksCsock, path,
2379: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
2380: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2381: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2382: goto fail;
2383: }
2384:
1.1.1.2 misho 2385: if (ready) {
2386: #ifdef USE_NG_NETFLOW
2387: #ifdef NG_NETFLOW_CONF_INGRESS
2388: if (b->iface.nfin_up || b->iface.nfout_up)
1.1.1.3 ! misho 2389: IfaceSetupNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 1);
1.1.1.2 misho 2390: #else /* NG_NETFLOW_CONF_INGRESS */
2391: if (b->iface.nfin_up)
1.1.1.3 ! misho 2392: IfaceSetupNetflow(b, 1, 0, 1);
1.1.1.2 misho 2393:
2394: if (b->iface.nfout_up)
1.1.1.3 ! misho 2395: IfaceSetupNetflow(b, 0, 1, 1);
1.1.1.2 misho 2396: #endif /* NG_NETFLOW_CONF_INGRESS */
2397: #endif /* USE_NG_NETFLOW */
2398: }
2399:
1.1.1.3 ! misho 2400: #ifdef USE_NG_BPF
! 2401: IfaceSetupLimits(b);
! 2402: #endif
! 2403:
1.1 misho 2404: /* OK */
2405: return(0);
2406:
2407: fail:
2408: return(-1);
2409: }
2410:
2411: /*
2412: * IfaceNgIpv6Shutdown()
2413: */
2414:
2415: static void
2416: IfaceNgIpv6Shutdown(Bund b)
2417: {
2418: char path[NG_PATHSIZ];
2419:
1.1.1.3 ! misho 2420: #ifdef USE_NG_BPF
! 2421: IfaceShutdownLimits(b); /* Limits must shutdown first to save final stats. */
! 2422: #endif
1.1 misho 2423: if (b->iface.tee6_up)
2424: IfaceShutdownTee(b, 1);
2425: b->iface.tee6_up = 0;
1.1.1.2 misho 2426: #ifdef USE_NG_NETFLOW
2427: #ifdef NG_NETFLOW_CONF_INGRESS
2428: if (b->iface.nfin_up || b->iface.nfout_up)
1.1.1.3 ! misho 2429: IfaceShutdownNetflow(b, b->iface.nfin_up, b->iface.nfout_up, 1);
1.1.1.2 misho 2430: b->iface.nfin_up = 0;
2431: b->iface.nfout_up = 0;
2432: #else /* NG_NETFLOW_CONF_INGRESS */
2433: if (b->iface.nfin_up)
1.1.1.3 ! misho 2434: IfaceShutdownNetflow(b, 1, 0, 1);
1.1.1.2 misho 2435: b->iface.nfin_up = 0;
2436: if (b->iface.nfout_up)
1.1.1.3 ! misho 2437: IfaceShutdownNetflow(b, 0, 1, 1);
1.1.1.2 misho 2438: b->iface.nfout_up = 0;
2439: #endif /* NG_NETFLOW_CONF_INGRESS */
2440: #endif
1.1 misho 2441:
2442: snprintf(path, sizeof(path), "[%x]:", b->nodeID);
2443: NgFuncDisconnect(gLinksCsock, b->name, path, NG_PPP_HOOK_IPV6);
2444:
2445: snprintf(path, sizeof(path), "%s:", b->iface.ngname);
2446: NgFuncDisconnect(gLinksCsock, b->name, path, NG_IFACE_HOOK_INET6);
2447: }
2448:
2449: #ifdef USE_NG_NAT
2450: static int
2451: IfaceInitNAT(Bund b, char *path, char *hook)
2452: {
2453: NatState const nat = &b->iface.nat;
2454: struct ngm_mkpeer mp;
2455: struct ngm_name nm;
2456: struct in_addr ip;
2457: #ifdef NG_NAT_LOG
2458: struct ng_nat_mode mode;
2459: #endif
2460: Log(LG_IFACE2, ("[%s] IFACE: Connecting NAT", b->name));
2461:
2462: strcpy(mp.type, NG_NAT_NODE_TYPE);
2463: strcpy(mp.ourhook, hook);
2464: strcpy(mp.peerhook, NG_NAT_HOOK_IN);
2465: if (NgSendMsg(gLinksCsock, path,
2466: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2467: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2468: b->name, NG_NAT_NODE_TYPE, path, mp.ourhook);
2469: return(-1);
2470: }
2471: strlcat(path, ".", NG_PATHSIZ);
2472: strlcat(path, hook, NG_PATHSIZ);
2473: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-nat", gPid, b->name);
2474: if (NgSendMsg(gLinksCsock, path,
2475: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2476: Perror("[%s] can't name %s node", b->name, NG_NAT_NODE_TYPE);
2477: return(-1);
2478: }
2479: strcpy(hook, NG_NAT_HOOK_OUT);
2480:
2481: /* Set NAT IP */
2482: if (u_addrempty(&nat->alias_addr)) {
2483: ip.s_addr = 1; // Set something just to make it ready
2484: } else {
2485: ip = nat->alias_addr.u.ip4;
2486: }
2487: if (NgSendMsg(gLinksCsock, path,
2488: NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR, &ip, sizeof(ip)) < 0)
2489: Perror("[%s] can't set NAT ip", b->name);
2490:
2491: #ifdef NG_NAT_LOG
2492: /* Set NAT mode */
2493: mode.flags = 0;
2494: if (Enabled(&nat->options, NAT_CONF_LOG))
2495: mode.flags |= NG_NAT_LOG;
2496: if (!Enabled(&nat->options, NAT_CONF_INCOMING))
2497: mode.flags |= NG_NAT_DENY_INCOMING;
2498: if (Enabled(&nat->options, NAT_CONF_SAME_PORTS))
2499: mode.flags |= NG_NAT_SAME_PORTS;
2500: if (Enabled(&nat->options, NAT_CONF_UNREG_ONLY))
2501: mode.flags |= NG_NAT_UNREGISTERED_ONLY;
2502:
2503: mode.mask = NG_NAT_LOG | NG_NAT_DENY_INCOMING |
2504: NG_NAT_SAME_PORTS | NG_NAT_UNREGISTERED_ONLY;
2505: if (NgSendMsg(gLinksCsock, path,
2506: NGM_NAT_COOKIE, NGM_NAT_SET_MODE, &mode, sizeof(mode)) < 0)
2507: Perror("[%s] can't set NAT mode", b->name);
2508:
2509: /* Set NAT target IP */
2510: if (!u_addrempty(&nat->target_addr)) {
2511: ip = nat->target_addr.u.ip4;
2512: if (NgSendMsg(gLinksCsock, path,
2513: NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR, &ip, sizeof(ip)) < 0) {
2514: Perror("[%s] can't set NAT target IP", b->name);
2515: }
2516: }
2517: #endif
2518:
2519: return(0);
2520: }
2521:
2522: static int
2523: IfaceSetupNAT(Bund b)
2524: {
2525: NatState const nat = &b->iface.nat;
2526: char path[NG_PATHSIZ];
1.1.1.2 misho 2527: #ifdef NG_NAT_DESC_LENGTH
1.1 misho 2528: int k;
1.1.1.2 misho 2529: union {
2530: u_char buf[sizeof(struct ng_mesg) + sizeof(uint32_t)];
2531: struct ng_mesg reply;
2532: } u;
2533: uint32_t *const nat_id = (uint32_t *)(void *)u.reply.data;
2534: #endif
1.1 misho 2535:
1.1.1.3 ! misho 2536: snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name);
1.1 misho 2537: if (u_addrempty(&nat->alias_addr)) {
2538: if (NgSendMsg(gLinksCsock, path,
2539: NGM_NAT_COOKIE, NGM_NAT_SET_IPADDR,
2540: &b->iface.self_addr.addr.u.ip4,
2541: sizeof(b->iface.self_addr.addr.u.ip4)) < 0) {
2542: Perror("[%s] can't set NAT ip", b->name);
2543: return (-1);
2544: }
2545: }
2546: #ifdef NG_NAT_DESC_LENGTH
2547: /* redirect-port */
2548: for(k = 0; k < NM_PORT; k++) {
1.1.1.2 misho 2549: if(nat->nrpt_id[k] == -1) {
1.1 misho 2550: if (NgSendMsg(gLinksCsock, path,
2551: NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PORT, &nat->nrpt[k],
2552: sizeof(struct ng_nat_redirect_port)) < 0) {
2553: Perror("[%s] can't set NAT redirect-port", b->name);
1.1.1.2 misho 2554: } else {
2555: if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
2556: Perror("[%s] can't recv NAT redirect-port message", b->name);
2557: } else
2558: nat->nrpt_id[k] = *nat_id;
1.1 misho 2559: }
2560: }
2561: }
2562: /* redirect-addr */
2563: for(k = 0; k < NM_ADDR; k++) {
1.1.1.2 misho 2564: if(nat->nrad_id[k] == -1) {
1.1 misho 2565: if (NgSendMsg(gLinksCsock, path,
2566: NGM_NAT_COOKIE, NGM_NAT_REDIRECT_ADDR, &nat->nrad[k],
2567: sizeof(struct ng_nat_redirect_addr)) < 0) {
2568: Perror("[%s] can't set NAT redirect-addr", b->name);
1.1.1.2 misho 2569: } else {
2570: if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
2571: Perror("[%s] can't recv NAT redirect-addr message", b->name);
2572: } else
2573: nat->nrad_id[k] = *nat_id;
1.1 misho 2574: }
2575: }
2576: }
2577: /* redirect-proto */
2578: for(k = 0; k < NM_PROTO; k++) {
1.1.1.2 misho 2579: if(nat->nrpr_id[k] == -1) {
1.1 misho 2580: if (NgSendMsg(gLinksCsock, path,
2581: NGM_NAT_COOKIE, NGM_NAT_REDIRECT_PROTO, &nat->nrpr[k],
2582: sizeof(struct ng_nat_redirect_proto)) < 0) {
2583: Perror("[%s] can't set NAT redirect-proto", b->name);
1.1.1.2 misho 2584: } else {
2585: if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0) {
2586: Perror("[%s] can't recv NAT redirect-proto message", b->name);
2587: } else
2588: nat->nrpr_id[k] = *nat_id;
1.1 misho 2589: }
2590: }
2591: }
2592: #endif
2593: return (0);
2594: }
2595:
2596: static void
2597: IfaceShutdownNAT(Bund b)
2598: {
2599: char path[NG_PATHSIZ];
1.1.1.2 misho 2600: #ifdef NG_NAT_DESC_LENGTH
2601: NatState const nat = &b->iface.nat;
2602: int k;
2603: #endif
1.1 misho 2604:
2605: snprintf(path, sizeof(path), "mpd%d-%s-nat:", gPid, b->name);
2606: NgFuncShutdownNode(gLinksCsock, b->name, path);
1.1.1.2 misho 2607: #ifdef NG_NAT_DESC_LENGTH
2608: /* redirect-port */
2609: for(k = 0; k < NM_PORT; k++)
2610: if(nat->nrpt_id[k] > 0)
2611: nat->nrpt_id[k] = -1;
2612: /* redirect-addr */
2613: for(k = 0; k < NM_ADDR; k++)
2614: if(nat->nrad_id[k] > 0)
2615: nat->nrad_id[k] = -1;
2616: /* redirect-proto */
2617: for(k = 0; k < NM_PROTO; k++)
2618: if(nat->nrpr_id[k] > 0)
2619: nat->nrpr_id[k] = -1;
2620: #endif
1.1 misho 2621: }
2622: #endif /* USE_NG_NAT */
2623:
2624: static int
2625: IfaceInitTee(Bund b, char *path, char *hook, int v6)
2626: {
2627: struct ngm_mkpeer mp;
2628: struct ngm_name nm;
2629:
2630: Log(LG_IFACE2, ("[%s] IFACE: Connecting tee%s", b->name, v6?"6":""));
2631:
2632: strcpy(mp.type, NG_TEE_NODE_TYPE);
2633: strcpy(mp.ourhook, hook);
2634: strcpy(mp.peerhook, NG_TEE_HOOK_RIGHT);
2635: if (NgSendMsg(gLinksCsock, path,
2636: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2637: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2638: b->name, NG_TEE_NODE_TYPE, path, mp.ourhook);
2639: return(-1);
2640: }
2641: strlcat(path, ".", NG_PATHSIZ);
2642: strlcat(path, hook, NG_PATHSIZ);
2643: snprintf(nm.name, sizeof(nm.name), "%s-tee%s", b->iface.ifname, v6?"6":"");
2644: if (NgSendMsg(gLinksCsock, path,
2645: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2646: Perror("[%s] can't name %s node", b->name, NG_TEE_NODE_TYPE);
2647: return(-1);
2648: }
2649: strcpy(hook, NG_TEE_HOOK_LEFT);
2650:
2651: return(0);
2652: }
2653:
2654: static void
2655: IfaceShutdownTee(Bund b, int v6)
2656: {
2657: char path[NG_PATHSIZ];
2658:
2659: snprintf(path, sizeof(path), "%s-tee%s:", b->iface.ifname, v6?"6":"");
2660: NgFuncShutdownNode(gLinksCsock, b->name, path);
2661: }
2662:
2663: #ifdef USE_NG_IPACCT
2664: static int
2665: IfaceInitIpacct(Bund b, char *path, char *hook)
2666: {
2667: struct ngm_mkpeer mp;
2668: struct ngm_name nm;
2669: struct ngm_connect cn;
2670: char path1[NG_PATHSIZ];
2671: struct {
2672: struct ng_ipacct_mesg m;
2673: int data;
2674: } ipam;
2675:
2676: Log(LG_IFACE2, ("[%s] IFACE: Connecting ipacct", b->name));
2677:
2678: strcpy(mp.type, NG_TEE_NODE_TYPE);
2679: strcpy(mp.ourhook, hook);
2680: strcpy(mp.peerhook, NG_TEE_HOOK_RIGHT);
2681: if (NgSendMsg(gLinksCsock, path,
2682: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2683: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2684: b->name, NG_TEE_NODE_TYPE, path, mp.ourhook);
2685: return(-1);
2686: }
2687: strlcat(path, ".", NG_PATHSIZ);
2688: strlcat(path, hook, NG_PATHSIZ);
2689: snprintf(nm.name, sizeof(nm.name), "%s_acct_tee", b->iface.ifname);
2690: if (NgSendMsg(gLinksCsock, path,
2691: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2692: Perror("[%s] can't name %s node", b->name, NG_TEE_NODE_TYPE);
2693: return(-1);
2694: }
2695: strcpy(hook, NG_TEE_HOOK_LEFT);
2696:
2697: strcpy(mp.type, NG_IPACCT_NODE_TYPE);
2698: strcpy(mp.ourhook, NG_TEE_HOOK_RIGHT2LEFT);
2699: snprintf(mp.peerhook, sizeof(mp.peerhook), "%s_in", b->iface.ifname);
2700: if (NgSendMsg(gLinksCsock, path,
2701: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2702: Perror("[%s] can't create %s node at \"%s\"->\"%s\"",
2703: b->name, NG_IPACCT_NODE_TYPE, path, mp.ourhook);
2704: return(-1);
2705: }
2706: snprintf(path1, sizeof(path1), "%s.%s", path, NG_TEE_HOOK_RIGHT2LEFT);
2707: snprintf(nm.name, sizeof(nm.name), "%s_ip_acct", b->iface.ifname);
2708: if (NgSendMsg(gLinksCsock, path1,
2709: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2710: Perror("[%s] can't name %s node", b->name, NG_IPACCT_NODE_TYPE);
2711: return(-1);
2712: }
2713: strcpy(cn.ourhook, NG_TEE_HOOK_LEFT2RIGHT);
2714: strcpy(cn.path, NG_TEE_HOOK_RIGHT2LEFT);
2715: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s_out", b->iface.ifname);
2716: if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2717: sizeof(cn)) < 0) {
2718: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2719: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2720: return (-1);
2721: }
2722:
2723: snprintf(ipam.m.hname, sizeof(ipam.m.hname), "%s_in", b->iface.ifname);
2724: ipam.data = DLT_RAW;
2725: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_SETDLT,
2726: &ipam, sizeof(ipam)) < 0) {
2727: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2728: return (-1);
2729: }
2730: ipam.data = 10000;
2731: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_STHRS,
2732: &ipam, sizeof(ipam)) < 0) {
2733: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2734: return (-1);
2735: }
2736:
2737: snprintf(ipam.m.hname, sizeof(ipam.m.hname), "%s_out", b->iface.ifname);
2738: ipam.data = DLT_RAW;
2739: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_SETDLT,
2740: &ipam, sizeof(ipam)) < 0) {
2741: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2742: return (-1);
2743: }
2744: ipam.data = 10000;
2745: if (NgSendMsg(gLinksCsock, path1, NGM_IPACCT_COOKIE, NGM_IPACCT_STHRS,
2746: &ipam, sizeof(ipam)) < 0) {
2747: Perror("[%s] can't set DLT \"%s\"->\"%s\"", b->name, path, ipam.m.hname);
2748: return (-1);
2749: }
2750:
2751: return(0);
2752: }
2753:
2754: static void
2755: IfaceShutdownIpacct(Bund b)
2756: {
2757: char path[NG_PATHSIZ];
2758:
2759: snprintf(path, sizeof(path), "%s_acct_tee:", b->iface.ifname);
2760: NgFuncShutdownNode(gLinksCsock, b->name, path);
2761: }
2762: #endif
2763:
2764: #ifdef USE_NG_NETFLOW
2765: static int
1.1.1.2 misho 2766: IfaceInitNetflow(Bund b, char *path, char *hook, char in, char out, int v6)
1.1 misho 2767: {
2768: struct ngm_connect cn;
2769: int nif;
2770:
2771: #ifdef NG_NETFLOW_CONF_INGRESS
1.1.1.3 ! misho 2772: nif = gNetflowIface + b->id*2;
1.1 misho 2773: #else
1.1.1.3 ! misho 2774: nif = gNetflowIface + b->id*4 + out*2;
1.1 misho 2775: #endif
1.1.1.3 ! misho 2776: nif += v6 ? 1 : 0;
1.1 misho 2777:
1.1.1.2 misho 2778: Log(LG_IFACE2, ("[%s] IFACE: Connecting netflow%s (%s)",
2779: b->name, v6?"6":"", out?"out":"in"));
1.1 misho 2780:
2781: /* Create global ng_netflow(4) node if not yet. */
2782: if (gNetflowNodeID == 0) {
2783: if (NgFuncInitGlobalNetflow())
2784: return(-1);
2785: }
2786:
2787: /* Connect ng_netflow(4) node to the ng_bpf(4)/ng_tee(4) node. */
2788: strcpy(cn.ourhook, hook);
2789: snprintf(cn.path, sizeof(cn.path), "[%x]:", gNetflowNodeID);
2790: #ifndef NG_NETFLOW_CONF_INGRESS
2791: if (out) {
2792: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d", NG_NETFLOW_HOOK_OUT,
2793: nif);
2794: } else {
2795: #endif
2796: snprintf(cn.peerhook, sizeof(cn.peerhook), "%s%d", NG_NETFLOW_HOOK_DATA,
2797: nif);
2798: #ifndef NG_NETFLOW_CONF_INGRESS
2799: }
2800: #endif
2801: if (NgSendMsg(gLinksCsock, path, NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2802: sizeof(cn)) < 0) {
2803: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2804: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2805: return (-1);
2806: }
2807: strlcat(path, ".", NG_PATHSIZ);
2808: strlcat(path, hook, NG_PATHSIZ);
2809: #ifndef NG_NETFLOW_CONF_INGRESS
2810: if (out) {
2811: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_DATA, nif);
2812: } else {
2813: #endif
2814: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_OUT, nif);
2815: #ifndef NG_NETFLOW_CONF_INGRESS
2816: }
2817: #endif
2818: return (0);
2819: }
2820:
2821: static int
1.1.1.3 ! misho 2822: IfaceSetupNetflow(Bund b, char in, char out, int v6)
1.1 misho 2823: {
2824: char path[NG_PATHSIZ];
2825: struct ng_netflow_setdlt nf_setdlt;
2826: struct ng_netflow_setifindex nf_setidx;
2827: #ifdef NG_NETFLOW_CONF_INGRESS
2828: struct ng_netflow_setconfig nf_setconf;
2829: #endif
2830: int nif;
2831:
2832: #ifdef NG_NETFLOW_CONF_INGRESS
1.1.1.3 ! misho 2833: nif = gNetflowIface + b->id*2;
1.1 misho 2834: #else
1.1.1.3 ! misho 2835: nif = gNetflowIface + b->id*4 + out*2;
1.1 misho 2836: #endif
1.1.1.3 ! misho 2837: nif += v6 ? 1 : 0;
! 2838:
1.1 misho 2839: /* Configure data link type and interface index. */
2840: snprintf(path, sizeof(path), "[%x]:", gNetflowNodeID);
2841: nf_setdlt.iface = nif;
2842: nf_setdlt.dlt = DLT_RAW;
2843: if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETDLT,
2844: &nf_setdlt, sizeof(nf_setdlt)) < 0) {
2845: Perror("[%s] can't configure data link type on %s", b->name, path);
2846: goto fail;
2847: }
2848: #ifdef NG_NETFLOW_CONF_INGRESS
2849: nf_setconf.iface = nif;
2850: nf_setconf.conf =
2851: (in?NG_NETFLOW_CONF_INGRESS:0) |
2852: (out?NG_NETFLOW_CONF_EGRESS:0) |
2853: (Enabled(&b->iface.options, IFACE_CONF_NETFLOW_ONCE)?NG_NETFLOW_CONF_ONCE:0);
2854: if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETCONFIG,
2855: &nf_setconf, sizeof(nf_setconf)) < 0) {
2856: Perror("[%s] can't set config on %s", b->name, path);
2857: goto fail;
2858: }
2859: #endif
2860: #ifndef NG_NETFLOW_CONF_INGRESS
2861: if (!out) {
2862: #endif
2863: nf_setidx.iface = nif;
2864: nf_setidx.index = if_nametoindex(b->iface.ifname);
2865: if (NgSendMsg(gLinksCsock, path, NGM_NETFLOW_COOKIE, NGM_NETFLOW_SETIFINDEX,
2866: &nf_setidx, sizeof(nf_setidx)) < 0) {
2867: Perror("[%s] can't configure interface index on %s", b->name, path);
2868: goto fail;
2869: }
2870: #ifndef NG_NETFLOW_CONF_INGRESS
2871: }
2872: #endif
2873:
2874: return 0;
2875: fail:
2876: return -1;
2877: }
2878:
2879: static void
1.1.1.3 ! misho 2880: IfaceShutdownNetflow(Bund b, char in, char out, int v6)
1.1 misho 2881: {
2882: char path[NG_PATHSIZ];
2883: char hook[NG_HOOKSIZ];
2884: int nif;
2885:
2886: #ifdef NG_NETFLOW_CONF_INGRESS
1.1.1.3 ! misho 2887: nif = gNetflowIface + b->id*2;
1.1 misho 2888: #else
1.1.1.3 ! misho 2889: nif = gNetflowIface + b->id*4 + out*2;
1.1 misho 2890: #endif
1.1.1.3 ! misho 2891: nif += v6 ? 1 : 0;
1.1 misho 2892:
2893: snprintf(path, NG_PATHSIZ, "[%x]:", gNetflowNodeID);
2894: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_DATA, nif);
2895: NgFuncDisconnect(gLinksCsock, b->name, path, hook);
2896: snprintf(hook, NG_HOOKSIZ, "%s%d", NG_NETFLOW_HOOK_OUT, nif);
2897: NgFuncDisconnect(gLinksCsock, b->name, path, hook);
2898: }
2899: #endif
2900:
2901: #if defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF))
2902: static int
2903: IfaceInitMSS(Bund b, char *path, char *hook)
2904: {
2905: struct ngm_mkpeer mp;
2906: struct ngm_name nm;
2907: #ifndef USE_NG_TCPMSS
2908: struct ngm_connect cn;
2909: #endif
2910:
2911: Log(LG_IFACE2, ("[%s] IFACE: Connecting tcpmssfix", b->name));
2912:
2913: #ifdef USE_NG_TCPMSS
2914: /* Create ng_tcpmss(4) node. */
2915: strcpy(mp.type, NG_TCPMSS_NODE_TYPE);
2916: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
2917: strcpy(mp.peerhook, "in");
2918: if (NgSendMsg(gLinksCsock, path,
2919: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2920: Perror("can't create %s node at \"%s\"->\"%s\"",
2921: NG_TCPMSS_NODE_TYPE, path, mp.ourhook);
2922: goto fail;
2923: }
2924:
2925: strlcat(path, ".", NG_PATHSIZ);
2926: strlcat(path, hook, NG_PATHSIZ);
2927: snprintf(hook, NG_HOOKSIZ, "out");
2928:
2929: /* Set the new node's name. */
2930: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-mss", gPid, b->name);
2931: if (NgSendMsg(gLinksCsock, path,
2932: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2933: Perror("can't name %s node", NG_TCPMSS_NODE_TYPE);
2934: goto fail;
2935: }
2936:
2937: #else
2938: /* Create a bpf node for SYN detection. */
2939: strcpy(mp.type, NG_BPF_NODE_TYPE);
2940: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
2941: strcpy(mp.peerhook, "ppp");
2942: if (NgSendMsg(gLinksCsock, path,
2943: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
2944: Perror("can't create %s node at \"%s\"->\"%s\"",
2945: NG_BPF_NODE_TYPE, path, mp.ourhook);
2946: goto fail;
2947: }
2948:
2949: strlcat(path, ".", NG_PATHSIZ);
2950: strlcat(path, hook, NG_PATHSIZ);
2951: strcpy(hook, "iface");
2952:
2953: /* Set the new node's name. */
2954: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-mss", gPid, b->name);
2955: if (NgSendMsg(gLinksCsock, path,
2956: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
2957: Perror("can't name tcpmssfix %s node", NG_BPF_NODE_TYPE);
2958: goto fail;
2959: }
2960:
2961: /* Connect to the bundle socket node. */
2962: strlcpy(cn.path, path, sizeof(cn.path));
2963: snprintf(cn.ourhook, sizeof(cn.ourhook), "i%d", b->id);
2964: strcpy(cn.peerhook, MPD_HOOK_TCPMSS_IN);
2965: if (NgSendMsg(gLinksCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2966: sizeof(cn)) < 0) {
2967: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2968: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2969: goto fail;
2970: }
2971:
2972: strlcpy(cn.path, path, sizeof(cn.path));
2973: snprintf(cn.ourhook, sizeof(cn.ourhook), "o%d", b->id);
2974: strcpy(cn.peerhook, MPD_HOOK_TCPMSS_OUT);
2975: if (NgSendMsg(gLinksCsock, ".:", NGM_GENERIC_COOKIE, NGM_CONNECT, &cn,
2976: sizeof(cn)) < 0) {
2977: Perror("[%s] can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
2978: b->name, path, cn.ourhook, cn.path, cn.peerhook);
2979: goto fail;
2980: }
2981: #endif /* USE_NG_TCPMSS */
2982:
2983: return (0);
2984: fail:
2985: return (-1);
2986: }
2987:
2988: /*
2989: * BundConfigMSS()
2990: *
2991: * Configure the tcpmss node to reduce MSS to given value.
2992: */
2993:
2994: static void
2995: IfaceSetupMSS(Bund b, uint16_t maxMSS)
2996: {
2997: #ifdef USE_NG_TCPMSS
2998: struct ng_tcpmss_config tcpmsscfg;
2999: char path[NG_PATHSIZ];
3000:
3001: snprintf(path, sizeof(path), "mpd%d-%s-mss:", gPid, b->name);
3002:
3003: /* Send configure message. */
3004: memset(&tcpmsscfg, 0, sizeof(tcpmsscfg));
3005: tcpmsscfg.maxMSS = maxMSS;
3006:
3007: snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "in");
3008: snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "out");
3009: if (NgSendMsg(gLinksCsock, path, NGM_TCPMSS_COOKIE, NGM_TCPMSS_CONFIG,
3010: &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
3011: Perror("[%s] can't configure %s node program", b->name, NG_TCPMSS_NODE_TYPE);
3012: }
3013: snprintf(tcpmsscfg.inHook, sizeof(tcpmsscfg.inHook), "out");
3014: snprintf(tcpmsscfg.outHook, sizeof(tcpmsscfg.outHook), "in");
3015: if (NgSendMsg(gLinksCsock, path, NGM_TCPMSS_COOKIE, NGM_TCPMSS_CONFIG,
3016: &tcpmsscfg, sizeof(tcpmsscfg)) < 0) {
3017: Perror("[%s] can't configure %s node program", b->name, NG_TCPMSS_NODE_TYPE);
3018: }
3019: #else
3020: union {
3021: u_char buf[NG_BPF_HOOKPROG_SIZE(TCPSYN_PROG_LEN)];
3022: struct ng_bpf_hookprog hprog;
3023: } u;
3024: struct ng_bpf_hookprog *const hp = &u.hprog;
3025: char hook[NG_HOOKSIZ];
3026:
3027: /* Setup programs for ng_bpf hooks */
3028: snprintf(hook, sizeof(hook), "i%d", b->id);
3029:
3030: memset(&u, 0, sizeof(u));
3031: strcpy(hp->thisHook, "ppp");
3032: hp->bpf_prog_len = TCPSYN_PROG_LEN;
3033: memcpy(&hp->bpf_prog, &gTCPSYNProg,
3034: TCPSYN_PROG_LEN * sizeof(*gTCPSYNProg));
3035: strcpy(hp->ifMatch, MPD_HOOK_TCPMSS_IN);
3036: strcpy(hp->ifNotMatch, "iface");
3037:
3038: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
3039: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
3040: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
3041:
3042: memset(&u, 0, sizeof(u));
3043: strcpy(hp->thisHook, MPD_HOOK_TCPMSS_IN);
3044: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3045: memcpy(&hp->bpf_prog, &gNoMatchProg,
3046: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3047: strcpy(hp->ifMatch, "ppp");
3048: strcpy(hp->ifNotMatch, "ppp");
3049:
3050: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
3051: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
3052: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
3053:
3054: snprintf(hook, sizeof(hook), "o%d", b->id);
3055: memset(&u, 0, sizeof(u));
3056: strcpy(hp->thisHook, "iface");
3057: hp->bpf_prog_len = TCPSYN_PROG_LEN;
3058: memcpy(&hp->bpf_prog, &gTCPSYNProg,
3059: TCPSYN_PROG_LEN * sizeof(*gTCPSYNProg));
3060: strcpy(hp->ifMatch, MPD_HOOK_TCPMSS_OUT);
3061: strcpy(hp->ifNotMatch, "ppp");
3062:
3063: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
3064: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
3065: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
3066:
3067: memset(&u, 0, sizeof(u));
3068: strcpy(hp->thisHook, MPD_HOOK_TCPMSS_OUT);
3069: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3070: memcpy(&hp->bpf_prog, &gNoMatchProg,
3071: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3072: strcpy(hp->ifMatch, "iface");
3073: strcpy(hp->ifNotMatch, "iface");
3074:
3075: if (NgSendMsg(gLinksCsock, hook, NGM_BPF_COOKIE,
3076: NGM_BPF_SET_PROGRAM, hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0)
3077: Perror("[%s] can't set %s node program", b->name, NG_BPF_NODE_TYPE);
3078:
3079: #endif /* USE_NG_TCPMSS */
3080: }
3081:
3082: static void
3083: IfaceShutdownMSS(Bund b)
3084: {
3085: char path[NG_PATHSIZ];
3086:
3087: #ifdef USE_NG_TCPMSS
3088: snprintf(path, sizeof(path), "mpd%d-%s-mss:", gPid, b->name);
3089: NgFuncShutdownNode(gLinksCsock, b->name, path);
3090: #else
3091: snprintf(path, sizeof(path), "i%d", b->id);
3092: NgFuncShutdownNode(gLinksCsock, b->name, path);
3093: #endif
3094: }
3095: #endif /* defined(USE_NG_TCPMSS) || (!defined(USE_NG_TCPMSS) && defined(USE_NG_BPF)) */
3096:
3097: #ifdef USE_NG_BPF
3098: static int
3099: IfaceInitLimits(Bund b, char *path, char *hook)
3100: {
3101: struct ngm_mkpeer mp;
3102: struct ngm_name nm;
3103:
3104: if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
3105:
3106: Log(LG_IFACE2, ("[%s] IFACE: Connecting limits", b->name));
3107:
3108: /* Create a bpf node for traffic filtering. */
3109: strcpy(mp.type, NG_BPF_NODE_TYPE);
3110: strlcpy(mp.ourhook, hook, sizeof(mp.ourhook));
3111: strcpy(mp.peerhook, "ppp");
3112: if (NgSendMsg(gLinksCsock, path,
3113: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
3114: Perror("can't create %s node at \"%s\"->\"%s\"",
3115: NG_BPF_NODE_TYPE, path, mp.ourhook);
3116: goto fail;
3117: }
3118:
3119: strlcat(path, ".", NG_PATHSIZ);
3120: strlcat(path, hook, NG_PATHSIZ);
3121: strcpy(hook, "iface");
3122:
3123: b->iface.limitID = NgGetNodeID(gLinksCsock, path);
3124: if (b->iface.limitID == 0)
3125: Perror("can't get limits %s node ID", NG_BPF_NODE_TYPE);
3126:
3127: /* Set the new node's name. */
3128: snprintf(nm.name, sizeof(nm.name), "mpd%d-%s-lim", gPid, b->name);
3129: if (NgSendMsg(gLinksCsock, path,
3130: NGM_GENERIC_COOKIE, NGM_NAME, &nm, sizeof(nm)) < 0) {
3131: Perror("can't name limits %s node", NG_BPF_NODE_TYPE);
3132: goto fail;
3133: }
3134:
3135: }
3136:
3137: return (0);
3138: fail:
3139: return (-1);
3140: }
3141:
3142: /*
3143: * BundConfigLimits()
3144: *
3145: * Configure the bpf & car nodes.
3146: */
3147:
3148: static void
3149: IfaceSetupLimits(Bund b)
3150: {
3151: #define ACL_MAX_PROGLEN 65536
3152: union {
3153: u_char buf[NG_BPF_HOOKPROG_SIZE(ACL_MAX_PROGLEN)];
3154: struct ng_bpf_hookprog hprog;
3155: } *hpu;
3156: struct ng_bpf_hookprog *hp;
3157: struct ngm_connect cn;
3158: int i;
3159:
1.1.1.2 misho 3160: hpu = Malloc(MB_ACL, sizeof(*hpu));
1.1 misho 3161: hp = &hpu->hprog;
3162:
3163: if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
3164: char path[NG_PATHSIZ];
3165: int num, dir;
3166:
3167: snprintf(path, sizeof(path), "mpd%d-%s-lim:", gPid, b->name);
3168:
3169: for (dir = 0; dir < 2; dir++) {
3170: char inhook[2][NG_HOOKSIZ];
3171: char inhookn[2][NG_HOOKSIZ];
3172: char outhook[NG_HOOKSIZ];
3173: struct acl *l;
3174:
3175: if (dir == 0) {
3176: strcpy(inhook[0], "ppp");
3177: strcpy(outhook, "iface");
3178: } else {
3179: strcpy(inhook[0], "iface");
3180: strcpy(outhook, "ppp");
3181: }
3182: strcpy(inhook[1], "");
3183: num = 0;
3184: for (l = b->params.acl_limits[dir]; l; l = l->next) {
3185: char str[ACL_LEN];
3186: #define ACL_MAX_PARAMS 7 /* one more then max number of arguments */
3187: int ac;
3188: char *av[ACL_MAX_PARAMS];
3189: int p;
3190: char stathook[NG_HOOKSIZ];
3191: struct svcs *ss = NULL;
3192: struct svcssrc *sss = NULL;
3193:
3194: Log(LG_IFACE2, ("[%s] IFACE: limit %s#%d%s%s: '%s'",
3195: b->name, (dir?"out":"in"), l->number,
3196: ((l->name[0])?"#":""), l->name, l->rule));
3197: strlcpy(str, l->rule, sizeof(str));
3198: ac = ParseLine(str, av, ACL_MAX_PARAMS, 0);
3199: if (ac < 1 || ac >= ACL_MAX_PARAMS) {
3200: Log(LG_ERR, ("[%s] IFACE: incorrect limit: '%s'",
3201: b->name, l->rule));
3202: continue;
3203: }
3204:
3205: stathook[0] = 0;
1.1.1.2 misho 3206: memset(hpu, 0, sizeof(*hpu));
1.1 misho 3207: /* Prepare filter */
3208: if (strcasecmp(av[0], "all") == 0) {
3209: hp->bpf_prog_len = MATCH_PROG_LEN;
3210: memcpy(&hp->bpf_prog, &gMatchProg,
3211: MATCH_PROG_LEN * sizeof(*gMatchProg));
3212: } else if (strncasecmp(av[0], "flt", 3) == 0) {
3213: struct acl *f;
3214: int flt;
3215:
3216: flt = atoi(av[0] + 3);
3217: if (flt <= 0 || flt > ACL_FILTERS) {
3218: Log(LG_ERR, ("[%s] IFACE: incorrect filter number: '%s'",
3219: b->name, av[0]));
3220: } else if ((f = b->params.acl_filters[flt - 1]) == NULL &&
3221: (f = acl_filters[flt - 1]) == NULL) {
3222: Log(LG_ERR, ("[%s] IFACE: Undefined filter: '%s'",
3223: b->name, av[0]));
3224: } else {
3225: struct bpf_program pr;
3226: char *buf;
3227: int bufbraces;
3228:
3229: #define ACL_BUF_SIZE 256*1024
1.1.1.2 misho 3230: buf = Malloc(MB_ACL, ACL_BUF_SIZE);
1.1 misho 3231: buf[0] = 0;
3232: bufbraces = 0;
3233: while (f) {
3234: char *b1, *b2, *sbuf;
1.1.1.2 misho 3235: sbuf = Mstrdup(MB_ACL, f->rule);
1.1 misho 3236: b2 = sbuf;
3237: b1 = strsep(&b2, " ");
3238: if (b2 != NULL) {
3239: if (strcasecmp(b1, "match") == 0) {
3240: strlcat(buf, "( ", ACL_BUF_SIZE);
3241: strlcat(buf, b2, ACL_BUF_SIZE);
3242: strlcat(buf, " ) ", ACL_BUF_SIZE);
3243: if (f->next) {
3244: strlcat(buf, "|| ( ", ACL_BUF_SIZE);
3245: bufbraces++;
3246: }
3247: } else if (strcasecmp(b1, "nomatch") == 0) {
3248: strlcat(buf, "( not ( ", ACL_BUF_SIZE);
3249: strlcat(buf, b2, ACL_BUF_SIZE);
3250: strlcat(buf, " ) ) ", ACL_BUF_SIZE);
3251: if (f->next) {
3252: strlcat(buf, "&& ( ", ACL_BUF_SIZE);
3253: bufbraces++;
3254: }
3255: } else {
3256: Log(LG_ERR, ("[%s] IFACE: filter action '%s' is unknown",
3257: b->name, b1));
3258: }
3259: };
3260: Freee(sbuf);
3261: f = f->next;
3262: }
3263: for (i = 0; i < bufbraces; i++)
3264: strlcat(buf, ") ", ACL_BUF_SIZE);
3265: Log(LG_IFACE2, ("[%s] IFACE: flt%d: '%s'",
3266: b->name, flt, buf));
3267:
3268: if (pcap_compile_nopcap((u_int)-1, DLT_RAW, &pr, buf, 1, 0xffffff00)) {
3269: Log(LG_ERR, ("[%s] IFACE: filter '%s' compilation error",
3270: b->name, av[0]));
3271: /* Incorrect matches nothing. */
3272: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3273: memcpy(&hp->bpf_prog, &gNoMatchProg,
3274: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3275: } else if (pr.bf_len > ACL_MAX_PROGLEN) {
3276: Log(LG_ERR, ("[%s] IFACE: filter '%s' is too long",
3277: b->name, av[0]));
3278: pcap_freecode(&pr);
3279: /* Incorrect matches nothing. */
3280: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3281: memcpy(&hp->bpf_prog, &gNoMatchProg,
3282: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3283: } else {
3284: hp->bpf_prog_len = pr.bf_len;
3285: memcpy(&hp->bpf_prog, pr.bf_insns,
3286: pr.bf_len * sizeof(struct bpf_insn));
3287: pcap_freecode(&pr);
3288: }
3289: Freee(buf);
3290: }
3291: } else {
3292: Log(LG_ERR, ("[%s] IFACE: incorrect filter: '%s'",
3293: b->name, av[0]));
3294: /* Incorrect matches nothing. */
3295: hp->bpf_prog_len = NOMATCH_PROG_LEN;
3296: memcpy(&hp->bpf_prog, &gNoMatchProg,
3297: NOMATCH_PROG_LEN * sizeof(*gNoMatchProg));
3298: }
3299:
3300: /* Prepare action */
3301: p = 1;
3302: if (ac == 1) {
3303: if (!l->next) {
3304: strcpy(hp->ifMatch, outhook);
3305: strcpy(inhookn[0], "");
3306: } else {
3307: sprintf(hp->ifMatch, "%d-%d-m", dir, num);
3308: sprintf(inhookn[0], "%d-%d-mi", dir, num);
3309:
3310: /* Connect nomatch hook to bpf itself. */
3311: strcpy(cn.ourhook, hp->ifMatch);
3312: strcpy(cn.path, path);
3313: strcpy(cn.peerhook, inhookn[0]);
3314: if (NgSendMsg(gLinksCsock, path,
3315: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
3316: Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
3317: b->name, path, cn.ourhook, cn.path, cn.peerhook);
3318: }
3319: strcpy(stathook, inhookn[0]);
3320: }
3321: } else if (strcasecmp(av[p], "pass") == 0) {
3322: strcpy(hp->ifMatch, outhook);
3323: strcpy(inhookn[0], "");
3324: } else if (strcasecmp(av[p], "deny") == 0) {
3325: strcpy(hp->ifMatch, "deny");
3326: strcpy(inhookn[0], "");
3327: #ifdef USE_NG_CAR
3328: } else if ((strcasecmp(av[p], "shape") == 0) ||
3329: (strcasecmp(av[p], "rate-limit") == 0)) {
3330: struct ngm_mkpeer mp;
3331: struct ng_car_bulkconf car;
3332: char tmppath[NG_PATHSIZ];
3333:
3334: sprintf(hp->ifMatch, "%d-%d-m", dir, num);
3335:
3336: /* Create a car node for traffic shaping. */
3337: strcpy(mp.type, NG_CAR_NODE_TYPE);
3338: snprintf(mp.ourhook, sizeof(mp.ourhook), "%d-%d-m", dir, num);
3339: strcpy(mp.peerhook, ((dir == 0)?NG_CAR_HOOK_LOWER:NG_CAR_HOOK_UPPER));
3340: if (NgSendMsg(gLinksCsock, path,
3341: NGM_GENERIC_COOKIE, NGM_MKPEER, &mp, sizeof(mp)) < 0) {
3342: Perror("[%s] IFACE: can't create %s node at \"%s\"->\"%s\"",
3343: b->name, NG_CAR_NODE_TYPE, path, mp.ourhook);
3344: }
3345:
3346: snprintf(tmppath, sizeof(tmppath), "%s%d-%d-m", path, dir, num);
3347:
3348: /* Connect car to bpf. */
3349: snprintf(cn.ourhook, sizeof(cn.ourhook), "%d-%d-mi", dir, num);
3350: strlcpy(cn.path, tmppath, sizeof(cn.path));
3351: strcpy(cn.peerhook, ((dir == 0)?NG_CAR_HOOK_UPPER:NG_CAR_HOOK_LOWER));
3352: if (NgSendMsg(gLinksCsock, path,
3353: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
3354: Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
3355: b->name, path, cn.ourhook, cn.path, cn.peerhook);
3356: }
3357:
3358: bzero(&car, sizeof(car));
3359:
3360: if (strcasecmp(av[p], "shape") == 0) {
3361: car.upstream.mode = NG_CAR_SHAPE;
3362: } else {
3363: car.upstream.mode = NG_CAR_RED;
3364: }
3365: p++;
3366:
3367: if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
3368: car.upstream.cir = atol(av[p]);
3369: p++;
3370: if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
3371: car.upstream.cbs = atol(av[p]);
3372: p++;
3373: if ((ac > p) && (av[p][0] >= '0') && (av[p][0] <= '9')) {
3374: car.upstream.ebs = atol(av[p]);
3375: p++;
3376: } else {
3377: car.upstream.ebs = car.upstream.cbs * 2;
3378: }
3379: } else {
3380: car.upstream.cbs = car.upstream.cir / 8;
3381: car.upstream.ebs = car.upstream.cbs * 2;
3382: }
3383: } else {
3384: car.upstream.cir = 8000;
3385: car.upstream.cbs = car.upstream.cir / 8;
3386: car.upstream.ebs = car.upstream.cbs * 2;
3387: }
3388: car.upstream.green_action = NG_CAR_ACTION_FORWARD;
3389: car.upstream.yellow_action = NG_CAR_ACTION_FORWARD;
3390: car.upstream.red_action = NG_CAR_ACTION_DROP;
3391:
3392: car.downstream = car.upstream;
3393:
3394: if (NgSendMsg(gLinksCsock, tmppath,
3395: NGM_CAR_COOKIE, NGM_CAR_SET_CONF, &car, sizeof(car)) < 0) {
3396: Perror("[%s] IFACE: can't set %s configuration",
3397: b->name, NG_CAR_NODE_TYPE);
3398: }
3399:
3400: if (ac > p) {
3401: if (strcasecmp(av[p], "pass") == 0) {
3402: union {
3403: u_char buf[NG_BPF_HOOKPROG_SIZE(MATCH_PROG_LEN)];
3404: struct ng_bpf_hookprog hprog;
3405: } hpu1;
3406: struct ng_bpf_hookprog *const hp1 = &hpu1.hprog;
3407:
3408: memset(&hpu1, 0, sizeof(hpu1));
3409: strcpy(hp1->ifMatch, outhook);
3410: strcpy(hp1->ifNotMatch, outhook);
3411: hp1->bpf_prog_len = MATCH_PROG_LEN;
3412: memcpy(&hp1->bpf_prog, &gMatchProg,
3413: MATCH_PROG_LEN * sizeof(*gMatchProg));
3414: sprintf(hp1->thisHook, "%d-%d-mi", dir, num);
3415: if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
3416: hp1, NG_BPF_HOOKPROG_SIZE(hp1->bpf_prog_len)) < 0) {
3417: Perror("[%s] IFACE: can't set %s node program",
3418: b->name, NG_BPF_NODE_TYPE);
3419: }
3420:
3421: strcpy(stathook, hp1->thisHook);
3422: strcpy(inhookn[0], "");
3423: } else {
3424: Log(LG_ERR, ("[%s] IFACE: unknown action: '%s'",
3425: b->name, av[p]));
3426: strcpy(inhookn[0], "");
3427: }
3428: } else {
3429: sprintf(inhookn[0], "%d-%d-mi", dir, num);
3430: strcpy(stathook, inhookn[0]);
3431: }
3432: #endif /* USE_NG_CAR */
3433: } else {
3434: Log(LG_ERR, ("[%s] IFACE: unknown action: '%s'",
3435: b->name, av[1]));
3436: strcpy(inhookn[0], "");
3437: }
3438:
3439: /* Prepare nomatch */
3440: if (l->next && strcasecmp(av[0], "all")) {
3441: /* If there is next limit and there is possible nomatch,
3442: * then pass nomatch there. */
3443: sprintf(hp->ifNotMatch, "%d-%d-n", dir, num);
3444: sprintf(inhookn[1], "%d-%d-ni", dir, num);
3445:
3446: /* Connect nomatch hook to bpf itself. */
3447: strcpy(cn.ourhook, hp->ifNotMatch);
3448: strcpy(cn.path, path);
3449: strcpy(cn.peerhook, inhookn[1]);
3450: if (NgSendMsg(gLinksCsock, path,
3451: NGM_GENERIC_COOKIE, NGM_CONNECT, &cn, sizeof(cn)) < 0) {
3452: Perror("[%s] IFACE: can't connect \"%s\"->\"%s\" and \"%s\"->\"%s\"",
3453: b->name, path, cn.ourhook, cn.path, cn.peerhook);
3454: }
3455: } else {
3456: /* There is no next limit, pass nomatch. */
3457: strcpy(hp->ifNotMatch, outhook);
3458: strcpy(inhookn[1], "");
3459: }
3460:
3461: /* Remember how to collect stats for this limit */
3462: if (l->name[0]) {
3463: SLIST_FOREACH(ss, &b->iface.ss[dir], next) {
3464: if (strcmp(ss->name, l->name) == 0)
3465: break;
3466: }
3467: if (ss == NULL) {
1.1.1.2 misho 3468: ss = Malloc(MB_ACL, sizeof(*ss));
1.1 misho 3469: strlcpy(ss->name, l->name, sizeof(ss->name));
3470: SLIST_INIT(&ss->src);
3471: SLIST_INSERT_HEAD(&b->iface.ss[dir], ss, next);
3472: }
3473: if (stathook[0]) {
1.1.1.2 misho 3474: sss = Malloc(MB_ACL, sizeof(*sss));
1.1 misho 3475: strlcpy(sss->hook, stathook, sizeof(sss->hook));
3476: sss->type = SSSS_IN;
3477: SLIST_INSERT_HEAD(&ss->src, sss, next);
3478: }
3479: }
3480:
3481: for (i = 0; i < 2; i++) {
3482: if (inhook[i][0] != 0) {
3483: if (l->name[0] && !stathook[0]) {
1.1.1.2 misho 3484: sss = Malloc(MB_ACL, sizeof(*sss));
1.1 misho 3485: strlcpy(sss->hook, inhook[i], sizeof(sss->hook));
3486: sss->type = SSSS_MATCH;
3487: SLIST_INSERT_HEAD(&ss->src, sss, next);
3488: }
3489:
3490: strcpy(hp->thisHook, inhook[i]);
3491: if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
3492: hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
3493: Perror("[%s] IFACE: can't set %s node program",
3494: b->name, NG_BPF_NODE_TYPE);
3495: }
3496: }
3497: strcpy(inhook[i], inhookn[i]);
3498: }
3499:
3500: num++;
3501: }
3502:
3503: /* Connect left hooks to output */
3504: for (i = 0; i < 2; i++) {
3505: if (inhook[i][0] != 0) {
3506: memset(hpu, 0, sizeof(*hpu));
3507: strcpy(hp->thisHook, inhook[i]);
3508: hp->bpf_prog_len = MATCH_PROG_LEN;
3509: memcpy(&hp->bpf_prog, &gMatchProg,
3510: MATCH_PROG_LEN * sizeof(*gMatchProg));
3511: strcpy(hp->ifMatch, outhook);
3512: strcpy(hp->ifNotMatch, outhook);
3513: if (NgSendMsg(gLinksCsock, path, NGM_BPF_COOKIE, NGM_BPF_SET_PROGRAM,
3514: hp, NG_BPF_HOOKPROG_SIZE(hp->bpf_prog_len)) < 0) {
3515: Perror("[%s] IFACE: can't set %s node %s %s program (2)",
3516: b->name, NG_BPF_NODE_TYPE, path, hp->thisHook);
3517: }
3518: }
3519: }
3520: }
3521: }
3522: Freee(hpu);
3523: }
3524:
3525: static void
3526: IfaceShutdownLimits(Bund b)
3527: {
3528: char path[NG_PATHSIZ];
3529: struct svcs *ss;
3530: struct svcssrc *sss;
3531: struct svcstat curstats;
3532: int i;
3533:
3534: if (b->n_up > 0) {
3535: bzero(&curstats, sizeof(curstats));
3536: IfaceGetStats(b, &curstats);
3537: IfaceAddStats(&b->iface.prevstats, &curstats);
3538: IfaceFreeStats(&curstats);
3539: }
3540:
3541: if (b->params.acl_limits[0] || b->params.acl_limits[1]) {
3542: snprintf(path, sizeof(path), "[%x]:", b->iface.limitID);
3543: NgFuncShutdownNode(gLinksCsock, b->name, path);
3544: }
3545:
3546: for (i = 0; i < ACL_DIRS; i++) {
3547: while ((ss = SLIST_FIRST(&b->iface.ss[i])) != NULL) {
3548: while ((sss = SLIST_FIRST(&ss->src)) != NULL) {
3549: SLIST_REMOVE_HEAD(&ss->src, next);
3550: Freee(sss);
3551: }
3552: SLIST_REMOVE_HEAD(&b->iface.ss[i], next);
3553: Freee(ss);
3554: }
3555: }
3556: }
3557:
3558: void
3559: IfaceGetStats(Bund b, struct svcstat *stat)
3560: {
3561: char path[NG_PATHSIZ];
3562: struct svcs *ss;
3563: struct svcssrc *sss;
3564: int dir;
3565:
3566: union {
3567: u_char buf[sizeof(struct ng_mesg) + sizeof(struct ng_bpf_hookstat)];
3568: struct ng_mesg reply;
3569: } u;
3570: struct ng_bpf_hookstat *const hs = (struct ng_bpf_hookstat *)(void *)u.reply.data;
3571:
3572: snprintf(path, sizeof(path), "[%x]:", b->iface.limitID);
3573: for (dir = 0; dir < ACL_DIRS; dir++) {
3574: SLIST_FOREACH(ss, &b->iface.ss[dir], next) {
3575: struct svcstatrec *ssr;
3576:
3577: SLIST_FOREACH(ssr, &stat->stat[dir], next) {
3578: if (strcmp(ssr->name, ss->name) == 0)
3579: break;
3580: }
3581: if (!ssr) {
1.1.1.2 misho 3582: ssr = Malloc(MB_ACL, sizeof(*ssr));
1.1 misho 3583: strlcpy(ssr->name, ss->name, sizeof(ssr->name));
3584: SLIST_INSERT_HEAD(&stat->stat[dir], ssr, next);
3585: }
3586:
3587: SLIST_FOREACH(sss, &ss->src, next) {
3588: if (NgSendMsg(gLinksCsock, path,
3589: NGM_BPF_COOKIE, NGM_BPF_GET_STATS, sss->hook, strlen(sss->hook)+1) < 0)
3590: continue;
3591: if (NgRecvMsg(gLinksCsock, &u.reply, sizeof(u), NULL) < 0)
3592: continue;
3593:
3594: switch(sss->type) {
3595: case SSSS_IN:
3596: ssr->Packets += hs->recvFrames;
3597: ssr->Octets += hs->recvOctets;
3598: break;
3599: case SSSS_MATCH:
3600: ssr->Packets += hs->recvMatchFrames;
3601: ssr->Octets += hs->recvMatchOctets;
3602: break;
3603: case SSSS_NOMATCH:
3604: ssr->Packets += hs->recvFrames - hs->recvMatchFrames;
3605: ssr->Octets += hs->recvOctets - hs->recvMatchOctets;
3606: break;
3607: case SSSS_OUT:
3608: ssr->Packets += hs->xmitFrames;
3609: ssr->Octets += hs->xmitOctets;
3610: break;
3611: }
3612: }
3613: }
3614: }
3615: }
3616:
3617: void
3618: IfaceAddStats(struct svcstat *stat1, struct svcstat *stat2)
3619: {
3620: struct svcstatrec *ssr1, *ssr2;
3621: int dir;
3622:
3623: for (dir = 0; dir < ACL_DIRS; dir++) {
3624: SLIST_FOREACH(ssr2, &stat2->stat[dir], next) {
3625: SLIST_FOREACH(ssr1, &stat1->stat[dir], next)
3626: if (strcmp(ssr1->name, ssr2->name) == 0) {
3627: break;
3628: }
3629: if (!ssr1) {
1.1.1.2 misho 3630: ssr1 = Malloc(MB_ACL, sizeof(*ssr1));
1.1 misho 3631: strlcpy(ssr1->name, ssr2->name, sizeof(ssr1->name));
3632: SLIST_INSERT_HEAD(&stat1->stat[dir], ssr1, next);
3633: }
3634: ssr1->Packets += ssr2->Packets;
3635: ssr1->Octets += ssr2->Octets;
3636: }
3637: }
3638: }
3639:
3640: void
3641: IfaceFreeStats(struct svcstat *stat)
3642: {
3643: struct svcstatrec *ssr;
3644: int i;
3645:
3646: for (i = 0; i < ACL_DIRS; i++) {
3647: while ((ssr = SLIST_FIRST(&stat->stat[i])) != NULL) {
3648: SLIST_REMOVE_HEAD(&stat->stat[i], next);
3649: Freee(ssr);
3650: }
3651: }
3652: }
3653: #endif /* USE_NG_BPF */
3654:
3655: /*
3656: * IfaceSetName()
3657: */
3658:
3659: int
3660: IfaceSetName(Bund b, const char * ifname)
3661: {
3662: IfaceState const iface = &b->iface;
3663: struct ifreq ifr;
3664: int s;
3665:
3666: /* Do not rename interface on template */
3667: if (b->tmpl)
3668: return(0);
3669:
3670: /* Do not wait ioctl error "file already exist" */
3671: if (strncmp(iface->ifname, ifname, sizeof(iface->ifname)) == 0)
3672: return(0);
3673:
3674: /* Get socket */
3675: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1.1.1.2 misho 3676: Perror("[%s] IFACE: Can't get socket to set name", b->name);
1.1 misho 3677: return(-1);
3678: }
3679:
3680: /* Set name of interface */
3681: memset(&ifr, 0, sizeof(ifr));
3682: strlcpy(ifr.ifr_name, iface->ifname, sizeof(ifr.ifr_name));
3683: ifr.ifr_data = (caddr_t)ifname;
3684: Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" name to \"%s\"",
3685: b->name, iface->ifname, ifname));
3686:
3687: if (ioctl(s, SIOCSIFNAME, (caddr_t)&ifr) < 0) {
1.1.1.3 ! misho 3688: if (errno != EEXIST) {
! 3689: Perror("[%s] IFACE: ioctl(%s, SIOCSIFNAME)", b->name, iface->ifname);
! 3690: close(s);
! 3691: return(-1);
! 3692: }
1.1 misho 3693: }
3694:
3695: close(s);
3696: /* Save name */
3697: strlcpy(iface->ifname, ifname, sizeof(iface->ifname));
3698: return(0);
3699: }
3700:
3701: #ifdef SIOCSIFDESCR
3702: /*
3703: * IfaceSetDescr()
1.1.1.2 misho 3704: *
3705: * Set/clear our own interface description accessible in console/web interface
3706: * and kernel level interface description if it is available.
3707: *
3708: * Template may contain conversion specifications:
3709: *
3710: * %% expands to single % sign;
3711: * %a for interface local address;
3712: * %A for peer address;
3713: * %i for system interface index;
3714: * %I for interface name;
3715: * %l for name of bundle's first link
3716: * %M for peer MAC address of bundle's first link
1.1.1.3 ! misho 3717: * %o for local outer ("physical") address of bundle's first link
! 3718: * %O for peer outer ("physical") address of bundle's first link
! 3719: * %P for peer outer ("physical") port of bundle's first link
1.1.1.2 misho 3720: * %S for interface status (DoD/UP/DOWN)
3721: * %t for type of bundle's first link (pppoe, pptp, l2tp etc.)
3722: * %u for self auth name (or dash if self auth name not used)
3723: * %U for peer auth name (or dash if peer has not authenticated)
1.1 misho 3724: */
3725: int
1.1.1.2 misho 3726: IfaceSetDescr(Bund b, const char * template)
1.1 misho 3727: {
3728: IfaceState const iface = &b->iface;
3729: struct ifreq ifr;
1.1.1.2 misho 3730: int s;
3731: unsigned int ifdescr_maxlen = 1024; /* used as limit for old kernels */
1.1 misho 3732: char *newdescr;
1.1.1.2 misho 3733: size_t sz = sizeof(ifdescr_maxlen);
3734: char *limit, *ifname;
3735: const char *src;
3736: int proceed;
3737: char buf[64];
3738:
3739: static int mib[2] = { -1, 0 }; /* MIB for net.ifdescr_maxlen */
3740: size_t miblen = sizeof(mib) / sizeof(mib[0]);
3741:
3742: /*
3743: * Check whether running kernel supports interface description.
3744: * Perform the check only once.
3745: */
3746: if (mib[0] < 0 && sysctlnametomib("net.ifdescr_maxlen", mib, &miblen) < 0) {
3747: mib[0] = 0;
3748: Perror("[%s] IFACE: sysctl net.ifdescr_maxlen failed", b->name);
3749: }
3750:
3751: /*
3752: * Fetch net.ifdescr_maxlen value every time to catch up with changes
3753: */
3754: if (mib[0] && sysctl(mib, 2, &ifdescr_maxlen, &sz, NULL, 0) < 0) {
3755: /* unexpected error from the kernel, use default value */
3756: Perror("[%s] IFACE: sysctl net.ifdescr_maxlen failed", b->name);
3757: ifdescr_maxlen = 1024;
1.1 misho 3758: }
3759:
1.1.1.2 misho 3760: newdescr = NULL;
3761: ifname = iface->ifname;
3762: if (iface->ifdescr != NULL) {
3763: Freee(iface->ifdescr);
3764: iface->ifdescr = NULL;
1.1 misho 3765: }
1.1.1.2 misho 3766: if ((src = template) != NULL) {
1.1 misho 3767:
1.1.1.2 misho 3768: /* Will use Mstrdup() later for iface->ifdescr to free extra memory */
3769: if ((iface->ifdescr = newdescr = Malloc(MB_IFACE, ifdescr_maxlen)) == NULL) {
3770: Log(LG_IFACE2, ("[%s] IFACE: no memory for interface %s description",
3771: b->name, ifname ? ifname : ""));
3772: return(-1);
3773: }
3774:
3775: /* ifdescr_maxlen includes terminating zero */
3776: limit = newdescr + ifdescr_maxlen - 1;
3777:
3778: /*
3779: * Perform template expansion
3780: */
3781: proceed = 1;
3782: while (proceed && *src && newdescr < limit) {
3783: if (*src != '%') { /* ordinary symbol, just copy it and proceed */
3784: *newdescr++ = *src++;
3785: continue;
3786: }
3787: if (!*(src+1)) { /* '%' at the end of template, just copy */
3788: *newdescr++ = *src++;
3789: continue;
3790: }
3791: switch(*++src) { /* expand */
3792: case '%': /* %% got replaced with single % */
3793: *newdescr++ = *src;
3794: break;
3795:
3796: #define DST_COPY(a) \
3797: do { const char *temp = a; \
3798: if (temp && *temp) { \
3799: if ((newdescr + strlen (temp)) <= limit) {\
3800: newdescr = stpcpy (newdescr, temp); \
3801: } else { \
3802: proceed = 0; \
3803: } \
3804: } else { \
3805: *newdescr++ = '-'; \
3806: } \
3807: } while(0)
3808:
3809: /* self address */
3810: case 'a':
3811: {
3812: char *sep;
3813: u_rangetoa(&iface->self_addr, buf, sizeof(buf));
3814: /* cut netmask */
3815: if ((sep = strchr(buf, '/')))
3816: *sep = '\0';
3817: DST_COPY(buf);
3818: }
3819: break;
3820: /* peer address */
3821: case 'A':
3822: {
1.1.1.3 ! misho 3823: u_addrtoa(&iface->peer_addr, buf, sizeof(buf));
1.1.1.2 misho 3824: DST_COPY(buf);
3825: }
3826: break;
3827: /* interface index */
3828: case 'i':
3829: {
1.1.1.3 ! misho 3830: snprintf(buf, sizeof(buf), "%u", iface->ifindex);
1.1.1.2 misho 3831: DST_COPY(buf);
3832: }
3833: break;
3834: /* interface name */
3835: case 'I':
3836: DST_COPY(iface->ifname);
3837: break;
3838: /* first link name */
3839: case 'l':
3840: DST_COPY(b->links[0] ? b->links[0]->name : NULL);
3841: break;
1.1.1.3 ! misho 3842: /* peer MAC address */
1.1.1.2 misho 3843: case 'M':
1.1.1.3 ! misho 3844: if (b->links[0]) {
1.1.1.2 misho 3845: PhysType const pt = b->links[0]->type;
3846: if (pt && pt->peermacaddr) {
1.1.1.3 ! misho 3847: (*pt->peermacaddr)(b->links[0], buf, sizeof(buf));
! 3848: DST_COPY(buf);
1.1.1.2 misho 3849: } else {
3850: DST_COPY("-");
3851: }
1.1.1.3 ! misho 3852: } else {
! 3853: DST_COPY("-");
! 3854: }
! 3855: break;
! 3856: /* local "physycal" address */
! 3857: case 'o':
! 3858: if (b->links[0] && PhysGetSelfAddr(b->links[0], buf, sizeof(buf)) == 0) {
! 3859: DST_COPY(buf);
! 3860: } else {
! 3861: DST_COPY("-");
! 3862: }
! 3863: break;
! 3864: /* peer "physycal" address */
! 3865: case 'O':
! 3866: if (b->links[0] && PhysGetPeerAddr(b->links[0], buf, sizeof(buf)) == 0) {
! 3867: DST_COPY(buf);
! 3868: } else {
! 3869: DST_COPY("-");
! 3870: }
! 3871: break;
! 3872: /* peer port */
! 3873: case 'P':
! 3874: if (b->links[0] && PhysGetPeerPort(b->links[0], buf, sizeof(buf)) == 0) {
! 3875: DST_COPY(buf);
1.1.1.2 misho 3876: } else {
3877: DST_COPY("-");
3878: }
3879: break;
3880: /* interface status */
3881: case 'S':
3882: DST_COPY(iface->up ? (iface->dod ? "DoD" : "UP") : "DOWN");
3883: break;
3884: /* first link type */
3885: case 't':
3886: DST_COPY(b->links[0] ? b->links[0]->type->name : NULL);
3887: break;
3888: /* self auth name */
3889: case 'u':
3890: DST_COPY(b->links[0] ? b->links[0]->lcp.auth.conf.authname : NULL);
3891: break;
3892: /* peer auth name */
3893: case 'U':
3894: DST_COPY(b->params.authname);
3895: break;
3896: #undef DST_COPY
3897: default: /* unrecognized specification, just copy */
3898: *newdescr++ = '%';
3899: if (newdescr < limit)
3900: *newdescr++ = *src;
3901: } /* switch(*++src) */
3902: ++src;
3903: } /* while */
3904: *newdescr = '\0';
3905:
3906: /* includes terminating zero */
3907: sz = newdescr - iface->ifdescr + 1;
3908: if ((newdescr = Mstrdup(MB_IFACE, iface->ifdescr)) == NULL) {
3909: Log(LG_IFACE2, ("[%s] IFACE: no memory for interface %s description",
3910: b->name, ifname ? ifname : ""));
3911: Freee(iface->ifdescr);
3912: iface->ifdescr = NULL;
3913: return(-1);
3914: }
3915: Freee(iface->ifdescr);
3916: iface->ifdescr = newdescr;
3917: } /* template != NULL */
3918:
3919: /* Set description of interface */
3920: if (mib[0] == 0)
3921: return(0); /* do not bother kernel if it is too old */
3922:
3923: if (ifname == NULL || *ifname == '\0')
3924: return(0); /* we have not set system interface name yet */
1.1 misho 3925:
3926: /* Get socket */
3927: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
1.1.1.2 misho 3928: Perror("[%s] IFACE: Can't get socket to set description for %s",
3929: b->name, ifname);
1.1 misho 3930: return(-1);
3931: }
3932:
3933: memset(&ifr, 0, sizeof(ifr));
1.1.1.2 misho 3934: strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
3935:
3936: if (!newdescr || !*newdescr) { /* empty description or clearing request */
3937: ifr.ifr_buffer.buffer = NULL;
1.1 misho 3938: ifr.ifr_buffer.length = 0;
3939: Log(LG_IFACE2, ("[%s] IFACE: clearing \"%s\" description",
1.1.1.2 misho 3940: b->name, ifname));
1.1 misho 3941: } else {
1.1.1.2 misho 3942: ifr.ifr_buffer.length = (unsigned)sz;
1.1 misho 3943: ifr.ifr_buffer.buffer = newdescr;
3944: Log(LG_IFACE2, ("[%s] IFACE: setting \"%s\" description to \"%s\"",
1.1.1.2 misho 3945: b->name, ifname, newdescr));
1.1 misho 3946: }
3947:
3948: if (ioctl(s, SIOCSIFDESCR, (caddr_t)&ifr) < 0) {
1.1.1.2 misho 3949: Perror("[%s] IFACE: ioctl(%s, SIOCSIFDESCR, \"%s\")",
3950: b->name, ifname, newdescr ? newdescr : "" );
1.1 misho 3951: close(s);
3952: return(-1);
3953: }
3954: close(s);
3955: return(0);
3956: }
3957: #endif /* SIOCSIFDESCR */
3958: #ifdef SIOCAIFGROUP
3959: /*
3960: * IfaceAddGroup()
3961: */
3962:
3963: int
3964: IfaceAddGroup(Bund b, const char * ifgroup)
3965: {
3966: IfaceState const iface = &b->iface;
3967: struct ifgroupreq ifgr;
3968: int s, i;
3969:
3970: /* Do not add group on template */
3971: if (b->tmpl)
3972: return(0);
3973:
3974: if (ifgroup[0] && isdigit(ifgroup[strlen(ifgroup) - 1])) {
3975: Perror("[%s] IFACE: groupnames may not end in a digit", b->name);
3976: return(-1);
3977: }
3978:
3979: /* Get socket */
3980: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
3981: Perror("[%s] IFACE: Can't get socket to add group", b->name);
3982: return(-1);
3983: }
3984:
3985: /* Add interface group */
3986: memset(&ifgr, 0, sizeof(ifgr));
3987: strlcpy(ifgr.ifgr_name, iface->ifname, sizeof(ifgr.ifgr_name));
3988: strlcpy(ifgr.ifgr_group, ifgroup, sizeof(ifgr.ifgr_group));
3989:
3990: Log(LG_IFACE2, ("[%s] IFACE: adding interface %s to group %s",
3991: b->name, iface->ifname, ifgroup));
3992:
3993: i = ioctl(s, SIOCAIFGROUP, (caddr_t)&ifgr);
3994: if (i < 0 && i != EEXIST) {
3995: Perror("[%s] IFACE: ioctl(%s, SIOCAIFGROUP)", b->name, iface->ifname);
3996: close(s);
3997: return(-1);
3998: }
3999:
4000: close(s);
4001: return(0);
4002: }
4003:
4004: /*
4005: * IfaceDelGroup()
4006: */
4007: int
4008: IfaceDelGroup(Bund b, const char * ifgroup)
4009: {
4010: IfaceState const iface = &b->iface;
4011: struct ifgroupreq ifgr;
4012: int s;
4013:
4014: /* Get socket */
4015: if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
4016: Perror("[%s] IFACE: Can't get socket to delete from group", b->name);
4017: return(-1);
4018: }
4019:
4020: if (ifgroup[0] && isdigit(ifgroup[strlen(ifgroup) - 1])) {
4021: Perror("[%s] IFACE: groupnames may not end in a digit", b->name);
4022: return(-1);
4023: }
4024:
4025: /* Set interface group */
4026: memset(&ifgr, 0, sizeof(ifgr));
4027: strlcpy(ifgr.ifgr_name, iface->ifname, sizeof(ifgr.ifgr_name));
4028: strlcpy(ifgr.ifgr_group, ifgroup, sizeof(ifgr.ifgr_group));
4029:
4030: Log(LG_IFACE2, ("[%s] IFACE: remove interface %s from group %s",
4031: b->name, iface->ifname, ifgroup));
4032:
4033: if (ioctl(s, SIOCDIFGROUP, (caddr_t)&ifgr) == -1) {
4034: Perror("[%s] IFACE: ioctl(%s, SIOCDIFGROUP)", b->name, iface->ifname);
4035: close(s);
4036: return(-1);
4037: }
4038: close(s);
4039: return(0);
4040: }
4041: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>