diff --git a/Makefile.FreeBSD b/Makefile.FreeBSD index fa122c0..da39181 100644 --- a/Makefile.FreeBSD +++ b/Makefile.FreeBSD @@ -10,10 +10,10 @@ CRYPT_PREFIX ?= $(PREFIX) MANDIR ?= /usr/share/man CC ?= cc -CFLAGS := -c -fno-strict-aliasing -DNOODBC -DFD_SETSIZE=4096 -DWITH_POLL -DWITH_UN $(CFLAGS) +CFLAGS := -c -O3 -fno-strict-aliasing -DNOODBC -DFD_SETSIZE=4096 -DWITH_POLL -DWITH_UN $(CFLAGS) COUT = -o LN ?= ${CC} -LDFLAGS += -pthread -fno-strict-aliasing +LDFLAGS += -g -flto -pthread -fno-strict-aliasing # -lpthreads may be reuiured on some platforms instead of -pthreads # -ldl or -lld may be required for some platforms DCFLAGS ?= -fPIC diff --git a/Makefile.Linux b/Makefile.Linux index 64e976a..81f0be9 100644 --- a/Makefile.Linux +++ b/Makefile.Linux @@ -9,11 +9,11 @@ PREFIX ?= 3proxy_ CRYPT_PREFIX ?= $(PREFIX) CC ?= gcc -CFLAGS := -g -fPIC -O2 -fno-strict-aliasing -c -pthread -DWITHSPLICE -D_GNU_SOURCE -DGETHOSTBYNAME_R -D_THREAD_SAFE -D_REENTRANT -DNOODBC -DFD_SETSIZE=4096 -DWITH_POLL -DWITH_NETFILTER -D WITH_UN $(CFLAGS) +CFLAGS := -g -fPIC -O3 -fno-strict-aliasing -c -pthread -DWITHSPLICE -D_GNU_SOURCE -DGETHOSTBYNAME_R -D_THREAD_SAFE -D_REENTRANT -DNOODBC -DFD_SETSIZE=4096 -DWITH_POLL -DWITH_NETFILTER -D WITH_UN $(CFLAGS) COUT = -o LN ?= ${CC} DCFLAGS ?= -LDFLAGS := -fPIC -O2 -fno-strict-aliasing -pthread $(LDFLAGS) +LDFLAGS := -fPIC -O3 -fno-strict-aliasing -pthread $(LDFLAGS) DLFLAGS ?= -shared DLSUFFICS = .ld.so # -lpthreads may be reuqired on some platforms instead of -pthreads diff --git a/src/acl.c b/src/acl.c index 0718d02..cb5596e 100644 --- a/src/acl.c +++ b/src/acl.c @@ -45,7 +45,7 @@ int ACLmatches(struct ace* acentry, struct clientparam * param){ } if(!ipentry) return 0; } - if((acentry->dst && (!SAISNULL(¶m->req) || param->operation == UDPASSOC || param->operation==BIND)) || (acentry->dstnames && param->hostname)) { + if((acentry->dst && (!SAISNULL(¶m->req) || param->operation==BIND)) || (acentry->dstnames && param->hostname)) { for(ipentry = acentry->dst; ipentry; ipentry = ipentry->next) if(IPInentry((struct sockaddr *)¶m->req, ipentry)) { break; @@ -93,7 +93,7 @@ int ACLmatches(struct ace* acentry, struct clientparam * param){ } if(!ipentry && !hstentry) return 0; } - if(acentry->ports && (*SAPORT(¶m->req) || param->operation == UDPASSOC || param->operation == BIND)) { + if(acentry->ports && (*SAPORT(¶m->req) || param->operation == BIND)) { for (portentry = acentry->ports; portentry; portentry = portentry->next) if(ntohs(*SAPORT(¶m->req)) >= portentry->startport && ntohs(*SAPORT(¶m->req)) <= portentry->endport) { @@ -143,13 +143,14 @@ int checkACL(struct clientparam * param){ struct ace dup; int res=60,i=0; - if(param->operation < 256 && !(param->operation & CONNECT)){ + + if(param->operation < 256 && !(param->operation & (CONNECT|UDPASSOC))){ continue; } if(param->redirected && acentry->chains && SAISNULL(&acentry->chains->addr) && !*SAPORT(&acentry->chains->addr)) { continue; } - if(param->remsock != INVALID_SOCKET) { + if(param->remsock != INVALID_SOCKET && (param->operation != UDPASSOC || param->ctrlsocksrv != INVALID_SOCKET)) { return 0; } for(; i < conf.parentretries; i++){ diff --git a/src/common.c b/src/common.c index c04f3bf..6dbd83a 100644 --- a/src/common.c +++ b/src/common.c @@ -557,9 +557,10 @@ int doconnect(struct clientparam * param){ if (*SAFAMILY(¶m->sincl) == *SAFAMILY(¶m->req) && !memcmp(SAADDR(¶m->sincl), SAADDR(¶m->req), SAADDRLEN(¶m->req)) && *SAPORT(¶m->sincl) == *SAPORT(¶m->req)) return 519; - if (param->operation == ADMIN || param->operation == DNSRESOLVE || param->operation == BIND || param->operation == UDPASSOC) + if (param->operation == ADMIN || (( param->operation == DNSRESOLVE || param->operation == BIND || param->operation == UDPASSOC) && !param->redirected)) return 0; if (param->remsock != INVALID_SOCKET){ + if(param->operation == UDPASSOC) return 0; size = sizeof(param->sinsr); if(param->srv->so._getpeername(param->sostate, param->remsock, (struct sockaddr *)¶m->sinsr, &size)==-1) {return (14);} } @@ -632,7 +633,7 @@ int doconnect(struct clientparam * param){ return 12; } - if(param->operation >= 256 || (param->operation & CONNECT)){ + if(param->operation >= 256 || (param->operation & CONNECT) || param->redirected){ if(connectwithpoll(param, param->remsock,(struct sockaddr *)¶m->sinsr,SASIZE(¶m->sinsr),conf.timeouts[CONNECT_TO])) { return 13; } @@ -646,7 +647,6 @@ int doconnect(struct clientparam * param){ action = handleconnectflt(param); if(action != PASS) return 19; } - return 0; } diff --git a/src/proxy.h b/src/proxy.h index 2b3a9f2..e965a3c 100644 --- a/src/proxy.h +++ b/src/proxy.h @@ -35,7 +35,6 @@ #define _PASSWORD_LEN 256 #define MAXNSERVERS 5 -#define UDPBUFSIZE 16384 #define TCPBUFSIZE 65536 #define SRVBUFSIZE (param->srv->bufsize?param->srv->bufsize:((param->service == S_UDPPM)?UDPBUFSIZE:TCPBUFSIZE)) @@ -231,7 +230,7 @@ void dumpcounters(struct trafcount *tl, int counterd); int startconnlims (struct clientparam *param); void stopconnlims (struct clientparam *param); - +int socks5_udp_build_hdr(unsigned char *buf, PROXYSOCKADDRTYPE *addr); extern struct auth authfuncs[]; diff --git a/src/proxymain.c b/src/proxymain.c index edae276..4c98457 100644 --- a/src/proxymain.c +++ b/src/proxymain.c @@ -251,10 +251,6 @@ int MODULEMAINFUNC (int argc, char** argv){ unsigned char buf[256]; char *hostname=NULL; int opt = 1, isudp = 0, iscbl = 0, iscbc = 0; -#ifndef NOUDPMAIN - unsigned char *udpbuf = NULL; - int udplen = 0; -#endif unsigned char *cbc_string = NULL, *cbl_string = NULL; PROXYSOCKADDRTYPE cbsa; FILE *fp = NULL; @@ -343,7 +339,6 @@ int MODULEMAINFUNC (int argc, char** argv){ #ifndef NOUDPMAIN if(isudp) { if(!udp_table.ihashtable)inithashtable(&udp_table, 64, 256, 65536); - if(!(udpbuf = myalloc(UDPBUFSIZE))) return 21; } #endif srv.service = defparam.service = childdef.service; @@ -926,15 +921,26 @@ int MODULEMAINFUNC (int argc, char** argv){ #ifndef NOUDPMAIN else { struct clientparam *toparam; - udplen = sockrecvfrom(NULL, srv.srvsock, (struct sockaddr *)&defparam.sincr, udpbuf, UDPBUFSIZE, 0); - if(udplen <= 0) continue; + + srv.udplen = sockrecvfrom(NULL, srv.srvsock, (struct sockaddr *)&defparam.sincr, srv.udpbuf, UDPBUFSIZE, 0); + if(srv.udplen <= 0) continue; _3proxy_sem_lock(udpinit); if(hashresolv(&udp_table, &defparam, &toparam, NULL)) { - srv.so._sendto(toparam->sostate, toparam->remsock, (char *)udpbuf, udplen, 0, (struct sockaddr *)&toparam->sinsr, SASIZE(&toparam->sinsr)); - _3proxy_sem_unlock(udpinit); - toparam->statscli64 += udplen; - toparam->nwrites++; - continue; + int i, len=0; + + if(toparam->udp_nhops - 1){ + for(i=1; i < toparam->udp_nhops - 1; i++){ + len+=socks5_udp_build_hdr(srv.udpbuf2+len, &toparam->udp_relay[i-1]); + } + len += socks5_udp_build_hdr(srv.udpbuf2+len, &toparam->req); + } + memcpy(srv.udpbuf2+len, srv.udpbuf, srv.udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : srv.udplen); + len += srv.udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : srv.udplen; + srv.so._sendto(toparam->sostate, toparam->remsock, (char *)srv.udpbuf2, len, 0, (struct sockaddr *)&toparam->sinsr, SASIZE(&toparam->sinsr)); + toparam->statscli64 += srv.udplen; + toparam->nwrites++; + _3proxy_sem_unlock(udpinit); + continue; } } #endif @@ -964,18 +970,6 @@ int MODULEMAINFUNC (int argc, char** argv){ #endif continue; } -#endif -#ifndef NOUDPMAIN - if(isudp) { - if(!(newparam->srvbuf = myalloc(UDPBUFSIZE))){ - freeparam(newparam); - _3proxy_sem_unlock(udpinit); - continue; - } - newparam->srvbufsize = UDPBUFSIZE; - newparam->srvinbuf = udplen; - memcpy(newparam->srvbuf, udpbuf, udplen); - } #endif newparam->prev = newparam->next = NULL; error = 0; @@ -1047,9 +1041,6 @@ int MODULEMAINFUNC (int argc, char** argv){ if(cbc_string)myfree(cbc_string); if(cbl_string)myfree(cbl_string); if(fp) fclose(fp); -#ifndef NOUDPMAIN - myfree(udpbuf); -#endif return 0; } diff --git a/src/redirect.c b/src/redirect.c index e64b1e7..1469796 100644 --- a/src/redirect.c +++ b/src/redirect.c @@ -24,7 +24,6 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc int len=0; unsigned char * user, *pass; - user = redir->extuser; pass = redir->extpass; if (!param->srvbufsize){ @@ -135,9 +134,9 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc int atyp; int skip_port = 0; buf[0] = 5; - buf[1] = 1; - buf[2] = user? 2 : 0; - if(socksend(param, param->remsock, buf, 3, conf.timeouts[CHAIN_TO]) != 3){ + buf[1] = user? 1 : 0; + buf[2] = 2; + if(socksend(param, param->remsock, buf, user?3:2, conf.timeouts[CHAIN_TO]) < 2){ return 51; } param->statssrv64+=3; @@ -172,9 +171,9 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc } } buf[0] = 5; - buf[1] = (param->operation == UDPASSOC && redir->type != R_SOCKS5B) ? 3 : 1; + buf[1] = (param->operation == UDPASSOC) ? 3 : 1; buf[2] = 0; - if (param->operation == UDPASSOC && redir->type != R_SOCKS5B) { + if (param->operation == UDPASSOC) { buf[3] = 1; memset(buf + 4, 0, 6); len = 10; @@ -219,7 +218,7 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc return 59; case 3: if (sockgetlinebuf(param, SERVER, buf, 1, EOF, conf.timeouts[CHAIN_TO]) != 1) return 59; - len = (unsigned char)buf[0]; + len = (unsigned char)buf[4]; if (sockgetlinebuf(param, SERVER, buf, len + 2, EOF, conf.timeouts[CHAIN_TO]) != len + 2) return 59; break; case 4: @@ -233,15 +232,17 @@ int clientnegotiate(struct chain * redir, struct clientparam * param, struct soc PROXYSOCKADDRTYPE *relay = ¶m->udp_relay[param->udp_nhops]; memset(relay, 0, sizeof(*relay)); if (atyp == 1) { - ((struct sockaddr_in *)relay)->sin_family = AF_INET; - memcpy(&((struct sockaddr_in *)relay)->sin_addr, buf, 4); - memcpy(&((struct sockaddr_in *)relay)->sin_port, buf + 4, 2); - if (param->udp_nhops == 0) param->sinsr = *relay; + *SAFAMILY(relay) = AF_INET; + memcpy(SAADDR(relay), buf, 4); + memcpy(SAPORT(relay), buf + 4, 2); + if (param->udp_nhops == 0) { + param->sinsr = *relay; + } param->udp_nhops++; } else if (atyp == 4) { - ((struct sockaddr_in6 *)relay)->sin6_family = AF_INET6; - memcpy(&((struct sockaddr_in6 *)relay)->sin6_addr, buf, 16); - memcpy(&((struct sockaddr_in6 *)relay)->sin6_port, buf + 16, 2); + *SAFAMILY(relay) = AF_INET6; + memcpy(SAADDR(relay), buf, 16); + memcpy(SAPORT(relay), buf + 16, 2); if (param->udp_nhops == 0) param->sinsr = *relay; param->udp_nhops++; } @@ -265,9 +266,9 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ struct chain * cur; struct chain * redir = NULL; int r2; + int saved = 0; - if(param->remsock != INVALID_SOCKET) { - return 0; + if(param->remsock != INVALID_SOCKET && param->operation != UDPASSOC) { } if((SAISNULL(¶m->req) || !*SAPORT(¶m->req)) && param->operation != UDPASSOC) { return 100; @@ -352,7 +353,13 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ else { param->sinsr = cur->addr; } - + if(param->operation == UDPASSOC){ + SOCKET s; + s = param->remsock; + param->remsock = INVALID_SOCKET; + param->ctrlsocksrv = s; + saved = 1; + } if((res = alwaysauth(param))){ return (res >= 10)? res : 60+res; } @@ -397,5 +404,15 @@ int handleredirect(struct clientparam * param, struct ace * acentry){ } if(!connected || !redir) return 0; - return clientnegotiate(redir, param, (struct sockaddr *)¶m->req, param->hostname); + res = clientnegotiate(redir, param, (struct sockaddr *)¶m->req, param->hostname); + if(saved){ + SOCKET s; + + s = param->ctrlsocksrv; + param->ctrlsocksrv = param->remsock; + param->remsock = s; + param->operation = UDPASSOC; + } + return res; + } diff --git a/src/sockmap.c b/src/sockmap.c index ff0a1aa..d6ff423 100644 --- a/src/sockmap.c +++ b/src/sockmap.c @@ -314,6 +314,11 @@ log(logbuf); } else { FROMCLIENTPIPE = TOSERVER = 0; + if(errno && errno != EINTR && errno != EAGAIN) { + SERVERTERMREAD = 1; + SERVERTERMWRITE = 1; + HASERROR |= 2; + } } } if(inserverpipe && !inserverbuf && FROMSERVERPIPE && TOCLIENT){ @@ -339,6 +344,11 @@ log(logbuf); } else { FROMSERVERPIPE = TOCLIENT = 0; + if(errno && errno != EINTR && errno != EAGAIN) { + CLIENTTERMREAD = 1; + CLIENTTERMWRITE = 1; + HASERROR |= 1; + } } } if(fromclient>inclientpipe && FROMCLIENT && TOCLIENTPIPE){ @@ -364,6 +374,11 @@ log(logbuf); CLIENTTERMREAD = 1; continue; } + if(errno && errno != EINTR && errno != EAGAIN) { + CLIENTTERMREAD = 1; + CLIENTTERMWRITE = 1; + continue; + } } else { #ifdef WITHLOG @@ -401,6 +416,11 @@ log(logbuf); SERVERTERMREAD = 1; continue; } + if(errno && errno != EINTR && errno != EAGAIN) { + SERVERTERMREAD = 1; + SERVERTERMWRITE = 1; + continue; + } } else { #ifdef WITHLOG @@ -499,11 +519,19 @@ log("done read from server to buf"); } } } - if (CLIENTTERMREAD && !inclientbuf && !SERVERTERMWRITE) { + if (CLIENTTERMREAD && !inclientbuf +#ifdef WITHSPLICE + && !inclientpipe +#endif + && !SERVERTERMWRITE) { SERVERTERMWRITE = 1; param->srv->so._shutdown(param->sostate, param->remsock, SHUT_WR); } - if (SERVERTERMREAD && !inserverbuf && !CLIENTTERMWRITE) { + if (SERVERTERMREAD && !inserverbuf +#ifdef WITHSPLICE + && !inserverpipe +#endif + && !CLIENTTERMWRITE) { CLIENTTERMWRITE = 1; param->srv->so._shutdown(param->sostate, param->clisock, SHUT_WR); } diff --git a/src/socks.c b/src/socks.c index d0624a0..edbe08c 100644 --- a/src/socks.c +++ b/src/socks.c @@ -85,7 +85,7 @@ void * sockschild(struct clientparam* param) { } if ((c = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_L], 0)) != 5) { RETURN(421); - } /* version */ + } } if( (command = sockgetcharcli(param, conf.timeouts[SINGLEBYTE_S], 0)) < 1 || command > 3){command = 0; RETURN(407);} /* command */ if(ver == 5){ diff --git a/src/structures.h b/src/structures.h index 1f49b9c..35e2921 100644 --- a/src/structures.h +++ b/src/structures.h @@ -183,7 +183,7 @@ int #endif #define MAX_HASH_SIZE (16) - +#define UDPBUFSIZE 16384 extern char* NULLADDR; typedef enum { @@ -517,6 +517,11 @@ struct srvparam { AUTHFUNC authfunc; PROXYFUNC pf; SOCKET srvsock, cbsock; +#ifndef NOUDPMAIN + unsigned char udpbuf[UDPBUFSIZE]; + unsigned char udpbuf2[UDPBUFSIZE]; + int udplen; +#endif int childcount; int maxchild; int backlog; diff --git a/src/udppm.c b/src/udppm.c index ee9971b..bc02715 100644 --- a/src/udppm.c +++ b/src/udppm.c @@ -29,11 +29,15 @@ static void udpparam2hash(const struct hashtable *ht, void *index, uint8_t *hash } struct hashtable udp_table = {udpparam2hash, udpparam2hash, sizeof(struct clientparam *), 8}; +int socks5_udp_build_hdr(unsigned char *buf, PROXYSOCKADDRTYPE *addr); void * udppmchild(struct clientparam* param) { int authres; + int i; + int len = 0; if(parsehostname((char *)param->srv->target, param, ntohs(param->srv->targetport))) { RETURN(201) } + #ifndef NOIPV6 memcpy(¶m->sinsl, *SAFAMILY(¶m->req) == AF_INET6 ? (struct sockaddr *)¶m->srv->extsa6 : (struct sockaddr *)¶m->srv->extsa, SASIZE(¶m->req)); #else @@ -53,13 +57,25 @@ void * udppmchild(struct clientparam* param) { authres = (*param->srv->authfunc)(param); if(authres) { RETURN(authres); } if(!param->srv->singlepacket)hashadd(&udp_table, param, ¶m, MAX_COUNTER_TIME); - param->srv->so._sendto(param->sostate, param->remsock, (char *)param->srvbuf, param->srvinbuf, 0, (struct sockaddr *)¶m->sinsr, SASIZE(¶m->sinsr)); + if(!param->srvbuf){ + if(!(param->srvbuf = myalloc(UDPBUFSIZE)))RETURN(11); + param->srvbufsize = UDPBUFSIZE; + } + if(param->udp_nhops){ + for(i=1; i < param->udp_nhops; i++){ + len+=socks5_udp_build_hdr(param->srvbuf+len, ¶m->udp_relay[i-1]); + } + len += socks5_udp_build_hdr(param->srvbuf+len, ¶m->req); + } + memcpy(param->srvbuf+len, param->srv->udpbuf, param->srv->udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : param->srv->udplen); + len += param->srv->udplen > UDPBUFSIZE - len?UDPBUFSIZE - len : param->srv->udplen; + param->srv->so._sendto(param->sostate, param->remsock, (char *)param->srvbuf, len, 0, (struct sockaddr *)¶m->sinsr, SASIZE(¶m->sinsr)); _3proxy_sem_unlock(udpinit); param->statscli64 += param->srvinbuf; param->srvinbuf = 0; param->nwrites++; param->clisock = param->srv->srvsock; - param->udp_nhops = 1; + param->udp_nhops++; param->waitserver64 = 0x7fffffffffffffff; param->res = udpsockmap(param, conf.timeouts[STRING_L]); _3proxy_sem_lock(udpinit); diff --git a/src/udpsockmap.c b/src/udpsockmap.c index 9cf9afe..24e4909 100644 --- a/src/udpsockmap.c +++ b/src/udpsockmap.c @@ -8,7 +8,7 @@ #include "proxy.h" -static int socks5_udp_build_hdr(unsigned char *buf, PROXYSOCKADDRTYPE *addr) +int socks5_udp_build_hdr(unsigned char *buf, PROXYSOCKADDRTYPE *addr) { buf[0] = buf[1] = buf[2] = 0; buf[3] = (*SAFAMILY(addr) == AF_INET) ? 1 : 4; @@ -57,7 +57,6 @@ int udpsockmap(struct clientparam *param, int timeo) int nhops = param->udp_nhops; int clisock_idx = -1, ctrlsock_idx = -1, ctrlsocksrv_idx = -1; int firstpacket = 1; - if (param->srvbufsize < UDPBUFSIZE) { unsigned char *newbuf = myrealloc(param->srvbuf, UDPBUFSIZE); if (!newbuf) return 21; @@ -92,7 +91,7 @@ int udpsockmap(struct clientparam *param, int timeo) for (;;) { res = param->srv->so._poll(param->sostate, fds, nfds, timeo * 1000); - if (res < 0) return 463; + if (res < 0) return 481; if (res == 0) return 92; /* datagram from client */ @@ -104,7 +103,7 @@ int udpsockmap(struct clientparam *param, int timeo) len = param->srv->so._recvfrom(param->sostate, param->clisock, (char *)param->srvbuf + recvoff, UDPBUFSIZE - recvoff, 0, (struct sockaddr *)&sin, &sasize); - if (len <= 0) return 464; + if (len <= 0) return 482; if (SAADDRLEN(&sin) != SAADDRLEN(¶m->sincr) || memcmp(SAADDR(&sin), SAADDR(¶m->sincr), SAADDRLEN(&sin))) @@ -119,7 +118,7 @@ int udpsockmap(struct clientparam *param, int timeo) if (nhops == 0) { int i; if (len < 10 || param->srvbuf[0] || param->srvbuf[1] || param->srvbuf[2]) - return 466; + return 483; switch (param->srvbuf[3]) { case 1: *SAFAMILY(¶m->sinsr) = AF_INET; @@ -127,14 +126,14 @@ int udpsockmap(struct clientparam *param, int timeo) i = 8; break; case 4: - if (len < 22) return 466; + if (len < 22) return 484; *SAFAMILY(¶m->sinsr) = AF_INET6; memcpy(SAADDR(¶m->sinsr), param->srvbuf + 4, 16); i = 20; break; case 3: { int sz = param->srvbuf[4], j; - if (len < 7 + sz) return 466; + if (len < 7 + sz) return 485; for (j = 4; j < 4 + sz; j++) param->srvbuf[j] = param->srvbuf[j + 1]; param->srvbuf[4 + sz] = 0; i = 5 + sz; @@ -175,7 +174,7 @@ int udpsockmap(struct clientparam *param, int timeo) len = param->srv->so._recvfrom(param->sostate, param->remsock, (char *)param->srvbuf + hdrsize, UDPBUFSIZE - hdrsize, 0, (struct sockaddr *)&from, &sasize); - if (len <= 0) return 468; + if (len <= 0) return 486; if (nhops >= 1) { if (!SAISNULL(¶m->sinsr) && *SAPORT(¶m->sinsr)) { if (SAADDRLEN(&from) != SAADDRLEN(¶m->sinsr) ||