X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/7b7135490b166cefca495e6fcfc4bd4f9158a9de..ce53e0ea9aad729511e8b315dcbed7122272c2a1:/polypath.c diff --git a/polypath.c b/polypath.c index ac6a18b..a8b2759 100644 --- a/polypath.c +++ b/polypath.c @@ -45,7 +45,8 @@ struct polypath { const char *const *ifname_pats; const char *const *monitor_command; bool_t permit_loopback; - LIST_HEAD(,interf) interfs; + LIST_HEAD(interf_list, interf) interfs_general; + struct interf_list interfs_dedicated; struct buffer_if lbuf; int monitor_fd; pid_t monitor_pid; @@ -53,6 +54,10 @@ struct polypath { int privsep_ipcsock_fd; }; +struct comm_clientinfo { + union iaddr dedicated; /* might be AF_UNSPEC */ +}; + static void polypath_phase_shutdown(void *sst, uint32_t newphase); #define LG 0, st->uc.cc.cl.description, &st->uc.cc.loc @@ -61,7 +66,7 @@ static const char *const default_loopback_ifname_pats[] = { "!lo", 0 }; static const char *const default_ifname_pats[] = { - "!tun*","!tap*","!sl*","!userv*", "*", 0 + "!tun*","!tap*","!sl*","!userv*", "@hippo*", "*", 0 }; static const char *const default_monitor_command[] = { @@ -93,7 +98,7 @@ static bool_t ifname_search_pats(struct polypath *st, struct cloc loc, const char *const *pati; for (pati=pats; *pati; pati++) { const char *pat=*pati; - if (*pat=='!' || *pat=='+') { *want_io=*pat; pat++; } + if (*pat=='!' || *pat=='+' || *pat=='@') { *want_io=*pat; pat++; } else if (*pat=='*' || isalnum((unsigned char)*pat)) { *want_io='+'; } else cfgfatal(loc,"polypath","invalid interface name pattern `%s'",pat); int match=fnmatch(pat,ifname,0); @@ -119,6 +124,21 @@ static char ifname_wanted(struct polypath *st, struct cloc loc, abort(); } +static struct comm_clientinfo *polypath_clientinfo(void *state, + dict_t *dict, struct cloc cloc) { + struct comm_clientinfo *clientinfo; + + NEW(clientinfo); + FILLZERO(*clientinfo); + clientinfo->dedicated.sa.sa_family=AF_UNSPEC; + + item_t *item = dict_find_item(dict,"dedicated-interface-addr", + False,"polypath",cloc); + if (item) string_item_to_iaddr(item,0,&clientinfo->dedicated, + "polypath"); + return clientinfo; +} + static int polypath_beforepoll(void *state, struct pollfd *fds, int *nfds_io, int *timeout_io) { @@ -151,7 +171,8 @@ typedef void bad_fn_type(struct polypath *st, void *badctx, typedef void polypath_ppml_callback_type(struct polypath *st, bad_fn_type *bad, void *badctx, - bool_t add, const char *ifname, const char *ifaddr, + bool_t add, char want, + const char *ifname, const char *ifaddr, const union iaddr *ia, int fd /* -1 if none yet */); struct ppml_bad_ctx { @@ -222,7 +243,6 @@ static void polypath_process_monitor_line(struct polypath *st, char *orgl, char want=ifname_wanted(st,st->uc.cc.loc,ifname); if (want=='!') DONT("unwanted interface name"); - assert(want=='+'); switch (ia.sa.sa_family) { case AF_INET6: { @@ -273,18 +293,20 @@ static void polypath_process_monitor_line(struct polypath *st, char *orgl, #undef DONT /* OK, process it */ - callback(st, bad,badctx, add,ifname,ifaddr,&ia,-1); + callback(st, bad,badctx, add,want, ifname,ifaddr,&ia,-1); out:; } -static void dump_pria(struct polypath *st, const char *ifname) +static void dump_pria(struct polypath *st, struct interf_list *interfs, + const char *ifname, char want) { #ifdef POLYPATH_DEBUG struct interf *interf; if (ifname) - lg_perror(LG,M_DEBUG,0, "polypath record ifaddr `%s'",ifname); - LIST_FOREACH(interf, &st->interfs, entry) { + lg_perror(LG,M_DEBUG,0, "polypath record ifaddr `%s' (%c)", + ifname, want); + LIST_FOREACH(interf, interfs, entry) { lg_perror(LG,M_DEBUG,0, " polypath interface `%s', nsocks=%d", interf->name, interf->socks.n_socks); int i; @@ -317,30 +339,39 @@ static bool_t polypath_make_socket(struct polypath *st, static void polypath_record_ifaddr(struct polypath *st, bad_fn_type *bad, void *badctx, - bool_t add, const char *ifname, + bool_t add, char want, + const char *ifname, const char *ifaddr, const union iaddr *ia, int fd) { struct udpcommon *uc=&st->uc; struct interf *interf=0; + int max_interfs; struct udpsock *us=0; - dump_pria(st,ifname); + struct interf_list *interfs; + switch (want) { + case '+': interfs=&st->interfs_general; max_interfs=st->max_interfs; break; + case '@': interfs=&st->interfs_dedicated; max_interfs=INT_MAX; + default: fatal("polypath: got bad want (%#x, %s)", want, ifname); + } + + dump_pria(st,interfs,ifname,want); int n_ifs=0; - LIST_FOREACH(interf,&st->interfs,entry) { + LIST_FOREACH(interf,interfs,entry) { if (!strcmp(interf->name,ifname)) goto found_interf; n_ifs++; } /* not found */ - if (n_ifs==st->max_interfs) BAD("too many interfaces"); + if (n_ifs==max_interfs) BAD("too many interfaces"); interf=malloc(sizeof(*interf)); if (!interf) BADE("malloc for new interface",errno); interf->name=0; interf->socks.n_socks=0; FILLZERO(interf->experienced_xmit_noaf); - LIST_INSERT_HEAD(&st->interfs,interf,entry); + LIST_INSERT_HEAD(interfs,interf,entry); interf->name=strdup(ifname); udp_socks_register(&st->uc,&interf->socks,interf->name); if (!interf->name) BADE("strdup interface name",errno); @@ -391,7 +422,7 @@ static void polypath_record_ifaddr(struct polypath *st, free(interf); } - dump_pria(st,0); + dump_pria(st,interfs,0,0); } static void subproc_problem(struct polypath *st, @@ -442,6 +473,52 @@ static void polypath_afterpoll_monitor(void *state, struct pollfd *fds, } /* Actual udp packet sending work */ + +static void polypath_sendmsg_interf(struct polypath *st, + struct interf *interf, + struct buffer_if *buf, + const struct comm_addr *dest, + const union iaddr *dedicated, + bool_t *allreasonable) +{ + int i; + int af=dest->ia.sa.sa_family; + bool_t wanted=False, attempted=False, reasonable=False; + + for (i=0; isocks.n_socks; i++) { + struct udpsock *us=&interf->socks.socks[i]; + if (dedicated && !iaddr_equal(dedicated, &us->addr, True)) + continue; + wanted=True; + if (af != us->addr.sa.sa_family) + continue; + attempted=True; + int r=sendto(us->fd,buf->start,buf->size, + 0,&dest->ia.sa,iaddr_socklen(&dest->ia)); + udp_sock_experienced(0,&st->uc,&interf->socks,us, + &dest->ia,af, r,errno); + if (r>=0) { + reasonable=True; + break; + } + if (!(errno==EAFNOSUPPORT || errno==ENETUNREACH)) + reasonable=True; + lg_perror(LG,M_DEBUG,errno,"%s [%s] xmit %"PRIu32" bytes to %s", + interf->name,iaddr_to_string(&us->addr), + buf->size,iaddr_to_string(&dest->ia)); + } + if (!wanted) + return; + + if (!attempted) + if (!interf->experienced_xmit_noaf[af]++) + lg_perror(LG,M_WARNING,0, + "%s has no suitable address to transmit %s", + interf->name, af_name(af)); + + *allreasonable *= reasonable; +} + static bool_t polypath_sendmsg(void *commst, struct buffer_if *buf, const struct comm_addr *dest, struct comm_clientinfo *clientinfo) @@ -449,36 +526,16 @@ static bool_t polypath_sendmsg(void *commst, struct buffer_if *buf, struct polypath *st=commst; struct interf *interf; bool_t allreasonable=True; - int af=dest->ia.sa.sa_family; - LIST_FOREACH(interf,&st->interfs,entry) { - int i; - bool_t attempted=False, reasonable=False; - for (i=0; isocks.n_socks; i++) { - struct udpsock *us=&interf->socks.socks[i]; - if (af != us->addr.sa.sa_family) - continue; - attempted=True; - int r=sendto(us->fd,buf->start,buf->size, - 0,&dest->ia.sa,iaddr_socklen(&dest->ia)); - udp_sock_experienced(0,&st->uc,&interf->socks,us, - &dest->ia,af, r,errno); - if (r>=0) { - reasonable=True; - break; - } - if (!(errno==EAFNOSUPPORT || errno==ENETUNREACH)) - reasonable=True; - lg_perror(LG,M_DEBUG,errno,"%s [%s] xmit %"PRIu32" bytes to %s", - interf->name,iaddr_to_string(&us->addr), - buf->size,iaddr_to_string(&dest->ia)); + LIST_FOREACH(interf,&st->interfs_general,entry) { + polypath_sendmsg_interf(st,interf,buf,dest, + 0, &allreasonable); + } + if (clientinfo && clientinfo->dedicated.sa.sa_family != AF_UNSPEC) { + LIST_FOREACH(interf,&st->interfs_dedicated,entry) { + polypath_sendmsg_interf(st,interf,buf,dest, + &clientinfo->dedicated, &allreasonable); } - if (!attempted) - if (!interf->experienced_xmit_noaf[af]++) - lg_perror(LG,M_WARNING,0, - "%s has no suitable address to transmit %s", - interf->name, af_name(af)); - allreasonable *= reasonable; } return allreasonable; } @@ -565,6 +622,7 @@ struct privsep_mdata { bool_t add; char ifname[100]; union iaddr ia; + char want; /* `+' or `@' */ }; static void papp_bad(struct polypath *st, void *badctx, @@ -608,7 +666,8 @@ static void polypath_afterpoll_privsep(void *state, struct pollfd *fds, fatal("polypath (privsep): got message data but bad AF %d",af); const char *addr_str=iaddr_to_string(&mdata->ia); polypath_record_ifaddr(st,papp_bad,(void*)addr_str, - mdata->add,mdata->ifname,addr_str, + mdata->add,mdata->want, + mdata->ifname,addr_str, &mdata->ia, st->privsep_incoming_fd); st->privsep_incoming_fd=-1; st->lbuf.size=0; @@ -661,7 +720,8 @@ static void polypath_afterpoll_privsep(void *state, struct pollfd *fds, static void privsep_handle_ifaddr(struct polypath *st, bad_fn_type *bad, void *badctx, - bool_t add, const char *ifname, + bool_t add, char want, + const char *ifname, const char *ifaddr, const union iaddr *ia, int fd_dummy) /* In child: handles discovered wanted interfaces, making sockets @@ -682,6 +742,7 @@ static void privsep_handle_ifaddr(struct polypath *st, size_t l=strlen(ifname); if (l>=sizeof(mdata.ifname)) BAD("interface name too long"); strcpy(mdata.ifname,ifname); + mdata.want=want; COPY_OBJ(mdata.ia,*ia); @@ -809,7 +870,9 @@ static void polypath_phase_childpersist(void *sst, uint32_t newphase) struct polypath *st=sst; struct interf *interf; - LIST_FOREACH(interf,&st->interfs,entry) + LIST_FOREACH(interf,&st->interfs_general,entry) + udp_socks_childpersist(&st->uc,&interf->socks); + LIST_FOREACH(interf,&st->interfs_dedicated,entry) udp_socks_childpersist(&st->uc,&interf->socks); } @@ -827,6 +890,8 @@ static list_t *polypath_apply(closure_t *self, struct cloc loc, COMM_APPLY_STANDARD(st,&st->uc.cc,"polypath",args); UDP_APPLY_STANDARD(st,&st->uc,"polypath"); + st->uc.cc.ops.clientinfo = polypath_clientinfo; + struct udpcommon *uc=&st->uc; struct commcommon *cc=&uc->cc; @@ -846,7 +911,8 @@ static list_t *polypath_apply(closure_t *self, struct cloc loc, st->permit_loopback=dict_read_bool(d,"permit-loopback",False, "polypath",cc->loc,False); - LIST_INIT(&st->interfs); + LIST_INIT(&st->interfs_general); + LIST_INIT(&st->interfs_dedicated); buffer_new(&st->lbuf,ADNS_ADDR2TEXT_BUFLEN+100); BUF_ALLOC(&st->lbuf,"polypath lbuf");