ssize_t socket_send6(int s,const char *buf,size_t len,const char ip[16],uint16 port,uint32 scope_id) { #ifdef LIBC_HAS_IP6 struct sockaddr_in6 si; #else struct sockaddr_in si; #endif byte_zero(&si,sizeof si); #ifdef LIBC_HAS_IP6 if (noipv6) { #endif if (ip6_isv4mapped(ip)) return socket_send4(s,buf,len,ip+12,port); if (byte_equal(ip,16,V6loopback)) return socket_send4(s,buf,len,ip4loopback,port); #ifdef LIBC_HAS_IP6 errno=EPROTONOSUPPORT; return -1; } si.sin6_family = AF_INET6; uint16_pack_big((char *) &si.sin6_port,port); byte_copy((char *) &si.sin6_addr,16,ip); #ifdef LIBC_HAS_SCOPE_ID si.sin6_scope_id=scope_id; #else si.sin6_scope_id=0; #endif return winsock2errno(sendto(s,buf,len,0,(void*) &si,sizeof si)); #else errno=EPROTONOSUPPORT; return -1; #endif }
void livesync_bind_mcast( ot_ip6 ip, uint16_t port) { char tmpip[4] = {0,0,0,0}; char *v4ip; if( !ip6_isv4mapped(ip)) exerr("v6 mcast support not yet available."); v4ip = ip+12; if( g_socket_in != -1 ) exerr("Error: Livesync listen ip specified twice."); if( ( g_socket_in = socket_udp4( )) < 0) exerr("Error: Cant create live sync incoming socket." ); ndelay_off(g_socket_in); if( socket_bind4_reuse( g_socket_in, tmpip, port ) == -1 ) exerr("Error: Cant bind live sync incoming socket." ); if( socket_mcjoin4( g_socket_in, groupip_1, v4ip ) ) exerr("Error: Cant make live sync incoming socket join mcast group."); if( ( g_socket_out = socket_udp4()) < 0) exerr("Error: Cant create live sync outgoing socket." ); if( socket_bind4_reuse( g_socket_out, v4ip, port ) == -1 ) exerr("Error: Cant bind live sync outgoing socket." ); socket_mcttl4(g_socket_out, 1); socket_mcloop4(g_socket_out, 0); }
size_t fmt_ip6c(char *s,const char ip[16]) { if (ip6_isv4mapped(ip)) return fmt_ip4(s,ip+12); else return fmt_ip6(s,ip); }
int socket_connect6(int s,const char ip[16],uint16 port,uint32 scope_id) { #ifdef LIBC_HAS_IP6 struct sockaddr_in6 sa; if (noipv6) { #endif if (ip6_isv4mapped(ip)) return socket_connect4(s,ip+12,port); if (byte_equal(ip,16,V6loopback)) return socket_connect4(s,ip4loopback,port); #ifdef LIBC_HAS_IP6 } byte_zero(&sa,sizeof sa); sa.sin6_family = PF_INET6; uint16_pack_big((char *) &sa.sin6_port,port); sa.sin6_flowinfo = 0; sa.sin6_scope_id = scope_id; byte_copy((char *) &sa.sin6_addr,16,ip); return connect(s,(struct sockaddr *) &sa,sizeof sa); #else errno=EPROTONOSUPPORT; return -1; #endif }
int socket_send6(int s,const char *buf,unsigned int len,const char ip[16],uint16 port,uint32 scope_id) { #ifdef LIBC_HAS_IP6 struct sockaddr_in6 sa; #else struct sockaddr_in sa; #endif byte_zero(&sa,sizeof sa); #ifdef LIBC_HAS_IP6 if (noipv6) { #endif if (ip6_isv4mapped(ip)) return socket_send4(s,buf,len,ip+12,port); if (byte_equal(ip,16,V6loopback)) return socket_send4(s,buf,len,ip4loopback,port); #ifdef LIBC_HAS_IP6 errno=error_proto; return -1; } sa.sin6_family = AF_INET6; uint16_pack_big((char *) &sa.sin6_port,port); byte_copy((char *) &sa.sin6_addr,16,ip); return sendto(s,buf,len,0,(struct sockaddr *) &sa,sizeof sa); #else errno=error_proto; return -1; #endif }
int socket_mcjoin6(int s,const char ip[16],int interface) { #ifdef LIBC_HAS_IP6 struct ipv6_mreq opt; #endif if (ip6_isv4mapped(ip)) return socket_mcjoin4(s,ip+12,ip); #ifdef LIBC_HAS_IP6 byte_copy(&opt.ipv6mr_multiaddr,16,ip); opt.ipv6mr_interface=interface; return setsockopt(s,IPPROTO_IPV6,IPV6_ADD_MEMBERSHIP,&opt,sizeof opt); #else errno=error_proto; return -1; #endif }
static int scan_ip6_port( const char *src, ot_ip6 ip, uint16 *port ) { const char *s = src; int off, bracket = 0; while( isspace(*s) ) ++s; if( *s == '[' ) ++s, ++bracket; /* for v6 style notation */ if( !(off = scan_ip6( s, ip ) ) ) return 0; s += off; if( *s == 0 || isspace(*s)) return s-src; if( *s == ']' && bracket ) ++s; if( !ip6_isv4mapped(ip)){ if( ( bracket && *(s) != ':' ) || ( *(s) != '.' ) ) return 0; s++; } else { if( *(s++) != ':' ) return 0; } if( !(off = scan_ushort (s, port ) ) ) return 0; return off+s-src; }
unsigned int ip6_fmt(char *s,const char ip[16]) { unsigned int len; unsigned int i; unsigned int temp; unsigned int compressing; int j; len = 0; compressing = 0; for (j=0; j<16; j+=2) { if (j==12 && ip6_isv4mapped(ip)) { temp=ip4_fmt(s,ip+12); len+=temp; if (s) s+=temp; break; } temp = ((unsigned long) (unsigned char) ip[j] << 8) + (unsigned long) (unsigned char) ip[j+1]; if (temp == 0) { if (!compressing) { compressing=1; if (j==0) { if (s) *s++=':'; ++len; } } } else { if (compressing) { compressing=0; if (s) *s++=':'; ++len; } i = fmt_xlong(s,temp); len += i; if (s) s += i; if (j<14) { if (s) *s++ = ':'; ++len; } } } /* if (s) *s=0; */ return len; }
unsigned int fmt_ip6(char *s,const char ip[16]) { unsigned long len,temp, k, pos0=0,len0=0, pos1=0, compr=0; for (k=0; k<16; k+=2) { if (ip[k]==0 && ip[k+1]==0) { if (!compr) { compr=1; pos1=k; } if (k==14) { k=16; goto last; } } else if (compr) { last: if ((temp=k-pos1) > len0) { len0=temp; pos0=pos1; } compr=0; } } for (len=0,k=0; k<16; k+=2) { if (k==12 && ip6_isv4mapped(ip)) { len += ip4_fmt(s,ip+12); break; } if (pos0==k && len0) { if (k==0) { ++len; if (s) *s++ = ':'; } ++len; if (s) *s++ = ':'; k += len0-2; continue; } temp = ((unsigned long) (unsigned char) ip[k] << 8) + (unsigned long) (unsigned char) ip[k+1]; temp = fmt_xlong(s,temp); len += temp; if (s) s += temp; if (k<14) { ++len; if (s) *s++ = ':'; } } return len; }
int main(int argc,char * const *argv) { const char *hostname; int opt; struct servent *se; char *x; unsigned long u; int s; int t; io_opt = ssl_io_opt_default; io_opt.timeout = 3600; while ((opt = getopt(argc,argv,"46dDvqQhHrR1UXx:t:T:u:g:l:b:B:c:Z:pPoO3IiEeSsaAw:nNyYuUjJ")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; case 'X': flagallownorules = 1; break; case 'x': fnrules = optarg; break; case 'B': banner = optarg; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; case 'Q': verbosity = 1; break; case 'P': flagparanoid = 0; break; case 'p': flagparanoid = 1; break; case 'O': flagkillopts = 1; break; case 'o': flagkillopts = 0; break; case 'H': flagremotehost = 0; break; case 'h': flagremotehost = 1; break; case 'R': flagremoteinfo = 0; break; case 'r': flagremoteinfo = 1; break; case 't': scan_ulong(optarg,&timeout); break; case 'T': scan_ulong(optarg,&ssltimeout); break; case 'w': scan_uint(optarg,&io_opt.timeout); break; case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); x = env_get("GID"); if (x) scan_ulong(x,&gid); break; case 'u': scan_ulong(optarg,&uid); break; case 'g': scan_ulong(optarg,&gid); break; case 'Z': netif=socket_getifidx(optarg); break; case '1': flag1 = 1; break; case '4': noipv6 = 1; break; case '6': forcev6 = 1; break; case 'l': localhost = optarg; break; case '3': flag3 = 1; break; case 'I': flagclientcert = 0; break; case 'i': flagclientcert = 1; break; case 'S': flagsslenv = 0; break; case 's': flagsslenv = 1; break; case 'E': flagtcpenv = 0; break; case 'e': flagtcpenv = 1; break; case 'n': case 'y': flagsslwait = 1; break; case 'N': case 'Y': flagsslwait = 0; break; case 'j': io_opt.just_shutdown = 1; break; case 'J': io_opt.just_shutdown = 0; break; default: usage(); } argc -= optind; argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv++; if (!hostname) usage(); if (str_equal(hostname,"")) hostname = "0"; x = *argv++; if (!x) usage(); prog = argv; if (!*argv) usage(); if (!x[scan_ulong(x,&u)]) localport = u; else { se = getservbyname(x,"tcp"); if (!se) strerr_die3x(111,FATAL,"unable to figure out port number for ",x); uint16_unpack_big((char*)&se->s_port,&localport); } if (x = env_get("VERIFYDEPTH")) { scan_ulong(x,&u); verifydepth = u; } if (x = env_get("CAFILE")) cafile = x; if (cafile && str_equal(cafile,"")) cafile = 0; if (x = env_get("CCAFILE")) ccafile = x; if (ccafile && str_equal(ccafile,"")) ccafile = 0; if (!flagclientcert) ccafile = 0; if (x = env_get("CADIR")) cadir = x; if (cadir && str_equal(cadir,"")) cadir= 0; if (x = env_get("CERTFILE")) certfile = x; if (certfile && str_equal(certfile,"")) certfile = 0; if (x = env_get("KEYFILE")) keyfile = x; if (keyfile && str_equal(keyfile,"")) keyfile = 0; if (x = env_get("DHFILE")) dhfile = x; if (dhfile && str_equal(dhfile,"")) dhfile = 0; if (x = env_get("CIPHERS")) ciphers = x; if (ciphers && str_equal(ciphers,"")) ciphers = 0; sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); if (str_equal(hostname,"0")) { byte_zero(localip,sizeof localip); } else { if (!stralloc_copys(&tmp,hostname)) strerr_die2x(111,FATAL,"out of memory"); if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); if (addresses.len < 16) strerr_die3x(111,FATAL,"no IP address for ",hostname); byte_copy(localip,16,addresses.s); if (ip6_isv4mapped(localip)) noipv6=1; } s = socket_tcp6(); if (s == -1) strerr_die2sys(111,FATAL,"unable to create socket: "); if (socket_bind6_reuse(s,localip,localport,netif) == -1) strerr_die2sys(111,FATAL,"unable to bind: "); if (socket_local6(s,localip,&localport,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get local address: "); if (socket_listen(s,backlog) == -1) strerr_die2sys(111,FATAL,"unable to listen: "); ndelay_off(s); localportstr[fmt_ulong(localportstr,localport)] = 0; if (flag1) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); buffer_puts(&b,localportstr); buffer_puts(&b,"\n"); buffer_flush(&b); } if (flag3) read_passwd(); ctx = ssl_server(); ssl_errstr(); if (!ctx) strerr_die2x(111,FATAL,"unable to create SSL context"); switch (ssl_certkey(ctx,certfile,keyfile,passwd_cb)) { case -1: strerr_die2x(111,FATAL,"unable to load certificate"); case -2: strerr_die2x(111,FATAL,"unable to load key"); case -3: strerr_die2x(111,FATAL,"key does not match certificate"); default: break; } if (!ssl_ca(ctx,cafile,cadir,verifydepth)) strerr_die2x(111,FATAL,"unable to load CA list"); if (!ssl_cca(ctx,ccafile)) strerr_die2x(111,FATAL,"unable to load client CA list"); if (!ssl_params(ctx,dhfile,rsalen)) strerr_die2x(111,FATAL,"unable to set cipher parameters"); if (!ssl_ciphers(ctx,ciphers)) strerr_die2x(111,FATAL,"unable to set cipher list"); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strnum2[fmt_ulong(strnum2,rsalen)] = 0; strerr_warn4("sslserver: cafile ",strnum," ",cafile,0); strerr_warn4("sslserver: ccafile ",strnum," ",ccafile,0); strerr_warn4("sslserver: cadir ",strnum," ",cadir,0); strerr_warn4("sslserver: cert ",strnum," ",certfile,0); strerr_warn4("sslserver: key ",strnum," ",keyfile,0); strerr_warn6("sslserver: param ",strnum," ",dhfile," ",strnum2,0); } close(0); open_read("/dev/null"); close(1); open_append("/dev/null"); printstatus(); for (;;) { while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); t = socket_accept6(s,remoteip,&remoteport,&netif); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); switch(fork()) { case 0: close(s); doit(t); strerr_die4sys(111,DROP,"unable to run ",*argv,": "); case -1: strerr_warn2(DROP,"unable to fork: ",&strerr_sys); --numchildren; printstatus(); } close(t); } }
void doit(int t) { int fakev4=0; int j; SSL *ssl; int wstat; uint32 scope_id; int sslctl[2]; char *s; unsigned long tmp_long; char sslctl_cmd; stralloc ssl_env = { 0 }; buffer ssl_env_buf; if (pipe(pi) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (pipe(po) == -1) strerr_die2sys(111,DROP,"unable to create pipe: "); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sslctl) == -1) strerr_die2sys(111,DROP,"unable to create socketpair: "); switch(fork()) { case -1: strerr_die2sys(111,DROP,"unable to fork: "); case 0: /* Child */ break; default: /* Parent */ close(pi[0]); close(po[1]); close(sslctl[1]); if ((s=env_get("SSL_CHROOT"))) if (chroot(s) == -1) strerr_die2x(111,DROPSSL,"unable to chroot"); if ((s=env_get("SSL_GID"))) { scan_ulong(s,&tmp_long); gid = tmp_long; } if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,DROPSSL,"unable to set gid: "); if ((s=env_get("SSL_UID"))) { scan_ulong(s,&tmp_long); uid = tmp_long; } if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,DROPSSL,"unable to set uid: "); /* This will exit on a fatal error or if the client quits * without activating SSL */ sslctl_cmd = ucspitls_master_wait_for_activation(sslctl[0]); /* If we got here, SSL must have been activated */ ssl = ssl_new(ctx,t); if (!ssl) strerr_die2x(111,DROP,"unable to create SSL instance"); if (ndelay_on(t) == -1) strerr_die2sys(111,DROP,"unable to set socket options: "); if (ssl_timeoutaccept(ssl,ssltimeout) == -1) strerr_die3x(111,DROP,"unable to accept SSL: ",ssl_error_str(ssl_errno)); if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn3("sslserver: ssl ",strnum," accept ",0); } if (flagclientcert) { switch(ssl_verify(ssl,verifyhost)) { case -1: strerr_die2x(111,DROP,"unable to verify client certificate"); case -2: strerr_die2x(111,DROP,"no client certificate"); case -3: strerr_die2x(111,DROP,"client name does not match certificate"); default: break; } } if (sslctl_cmd == 'Y') { ssl_server_env(ssl, &ssl_env); stralloc_0(&ssl_env); /* Add another NUL */ buffer_init(&ssl_env_buf,buffer_unixwrite,sslctl[0],NULL,0); if (buffer_putflush(&ssl_env_buf, ssl_env.s, ssl_env.len) == -1) { strerr_die2sys(111, FATAL, "unable to write SSL environment: "); } } else if (sslctl_cmd != 'y') { strerr_die2x(111,DROP,"Protocol error on SSL control descriptor: invalid command character read"); } if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (ssl_io(ssl,pi[1],po[0],io_opt) != 0) strerr_die3x(111,DROP,"unable to speak SSL: ",ssl_error_str(ssl_errno)); if (wait_nohang(&wstat) > 0) _exit(wait_exitcode(wstat)); ssl_close(ssl); _exit(0); } /* Child-only below this point */ if (close(sslctl[0]) != 0) { strerr_die2sys(111, DROP, "Error closing SSL control socket: "); } if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; else remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; strerr_warn4("sslserver: pid ",strnum," from ",remoteipstr,0); } if (socket_local6(t,localip,&localport,&scope_id) == -1) strerr_die2sys(111,DROP,"unable to get local address: "); if (fakev4) localipstr[ip4_fmt(localipstr,localip+12)] = 0; else localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name6(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) drop_nomem(); localhost = localhostsa.s; } env("PROTO",fakev4?"SSL":"SSL6"); env("SSLLOCALIP",localipstr); env("SSL6LOCALIP",localipstr); env("SSLLOCALPORT",localportstr); env("SSL6LOCALPORT",localportstr); env("SSLLOCALHOST",localhost); env("SSL6LOCALHOST",localhost); if (!fakev4 && scope_id) env("SSL6INTERFACE",socket_getifname(scope_id)); if (flagtcpenv) { env("TCPLOCALIP",localipstr); env("TCP6LOCALIP",localipstr); env("TCPLOCALPORT",localportstr); env("TCP6LOCALPORT",localportstr); env("TCPLOCALHOST",localhost); env("TCP6LOCALHOST",localhost); if (!fakev4 && scope_id) env("TCP6INTERFACE",socket_getifname(scope_id)); } if (flagremotehost) if (dns_name6(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) { verifyhost = remoteipstr; if (dns_ip6(&tmp,&remotehostsa) == 0) for (j = 0;j + 16 <= tmp.len;j += 16) if (byte_equal(remoteip,16,tmp.s + j)) { flagparanoid = 0; break; } } if (!flagparanoid) { if (!stralloc_0(&remotehostsa)) drop_nomem(); remotehost = remotehostsa.s; verifyhost = remotehostsa.s; } } env("SSLREMOTEIP",remoteipstr); env("SSL6REMOTEIP",remoteipstr); remoteipstr[ip6_fmt(remoteipstr,remoteip)]=0; env("SSLREMOTEPORT",remoteportstr); env("SSL6REMOTEPORT",remoteportstr); env("SSLREMOTEHOST",remotehost); env("SSL6REMOTEHOST",remotehost); if (flagtcpenv) { env("TCPREMOTEIP",remoteipstr); env("TCP6REMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); env("TCP6REMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); env("TCP6REMOTEHOST",remotehost); } if (flagremoteinfo) { if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) drop_nomem(); } env("SSLREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("SSL6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (flagtcpenv) { env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); env("TCP6REMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); } if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { int fakev4=0; char* temp; if (!forcev6 && ip6_isv4mapped(remoteip)) fakev4=1; if (fakev4) temp=remoteipstr+7; else temp=remoteipstr; if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"sslserver: ")) drop_nomem(); safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipstr); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipstr); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); if (gid) if (prot_gid(gid) == -1) strerr_die2sys(111,FATAL,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) strerr_die2sys(111,FATAL,"unable to set uid: "); close(pi[1]); close(po[0]); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); if (fcntl(sslctl[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,sslctl[1])]=0; setenv("SSLCTLFD",strnum,1); if (fcntl(pi[0],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,pi[0])]=0; setenv("SSLREADFD",strnum,1); if (fcntl(po[1],F_SETFD,0) == -1) strerr_die2sys(111,FATAL,"unable to clear close-on-exec flag"); strnum[fmt_ulong(strnum,po[1])]=0; setenv("SSLWRITEFD",strnum,1); if (flagsslwait) { if (fd_copy(0,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_copy(1,t) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } else { if (fd_move(0,pi[0]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 0: "); if (fd_move(1,po[1]) == -1) strerr_die2sys(111,DROP,"unable to set up descriptor 1: "); } if (flagkillopts) socket_ipoptionskill(t); if (!flagdelay) socket_tcpnodelay(t); if (*banner) { buffer_init(&b,buffer_unixwrite,1,bspace,sizeof bspace); if (buffer_putsflush(&b,banner) == -1) strerr_die2sys(111,DROP,"unable to print banner: "); } if (!flagsslwait) { strnum[fmt_ulong(strnum,flagsslenv)] = 0; strerr_warn2("flagsslenv: ", strnum, 0); ucspitls(flagsslenv,0,1); } pathexec(prog); strerr_die4sys(111,DROP,"unable to run ",*prog,": "); }
main(int argc,char **argv) { int fakev4=0; unsigned long u; int opt; char *x; int j; int s; int cloop; dns_random_init(seed); close(6); close(7); sig_ignore(sig_pipe); while ((opt = getopt(argc,argv,"46dDvqQhHrRi:p:t:T:l:I:")) != opteof) switch(opt) { case '4': noipv6 = 1; break; case '6': forcev6 = 1; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; case 'Q': verbosity = 1; break; case 'l': forcelocal = optarg; break; case 'H': flagremotehost = 0; break; case 'h': flagremotehost = 1; break; case 'R': flagremoteinfo = 0; break; case 'r': flagremoteinfo = 1; break; case 't': scan_ulong(optarg,&itimeout); break; case 'T': j = scan_ulong(optarg,&ctimeout[0]); if (optarg[j] == '+') ++j; scan_ulong(optarg + j,&ctimeout[1]); break; case 'i': if (!scan_ip6(optarg,iplocal)) usage(); break; case 'I': netif=socket_getifidx(optarg); break; case 'p': scan_ulong(optarg,&u); portlocal = u; break; default: usage(); } argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv; if (!hostname) usage(); if (!hostname[0] || str_equal(hostname,"0")) hostname = (noipv6?"127.0.0.1":"::1"); x = *++argv; if (!x) usage(); if (!x[scan_ulong(x,&u)]) portremote = u; else { struct servent *se; se = getservbyname(x,"tcp"); if (!se) strerr_die3x(111,FATAL,"unable to figure out port number for ",x); portremote = ntohs(se->s_port); /* i continue to be amazed at the stupidity of the s_port interface */ } if (!*++argv) usage(); if (!stralloc_copys(&tmp,hostname)) nomem(); if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) strerr_die4sys(111,FATAL,"temporarily unable to figure out IP address for ",hostname,": "); if (addresses.len < 16) strerr_die3x(111,FATAL,"no IP address for ",hostname); if (addresses.len == 16) { ctimeout[0] += ctimeout[1]; ctimeout[1] = 0; } for (cloop = 0;cloop < 2;++cloop) { if (!stralloc_copys(&moreaddresses,"")) nomem(); for (j = 0;j + 16 <= addresses.len;j += 4) { s = socket_tcp6(); if (s == -1) strerr_die2sys(111,FATAL,"unable to create socket: "); if (socket_bind6(s,iplocal,portlocal,netif) == -1) strerr_die2sys(111,FATAL,"unable to bind socket: "); if (timeoutconn6(s,addresses.s + j,portremote,ctimeout[cloop],netif) == 0) goto CONNECTED; close(s); if (!cloop && ctimeout[1] && (errno == error_timeout)) { if (!stralloc_catb(&moreaddresses,addresses.s + j,16)) nomem(); } else { strnum[fmt_ulong(strnum,portremote)] = 0; if (ip6_isv4mapped(addresses.s+j)) ipstr[ip4_fmt(ipstr,addresses.s + j + 12)] = 0; else ipstr[ip6_fmt(ipstr,addresses.s + j)] = 0; strerr_warn5(CONNECT,ipstr," port ",strnum,": ",&strerr_sys); } } if (!stralloc_copy(&addresses,&moreaddresses)) nomem(); } _exit(111); CONNECTED: if (!flagdelay) socket_tcpnodelay(s); /* if it fails, bummer */ if (socket_local6(s,iplocal,&portlocal,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get local address: "); if (!forcev6 && (ip6_isv4mapped(iplocal) || byte_equal(iplocal,16,V6any))) fakev4=1; if (!pathexec_env("PROTO",fakev4?"TCP":"TCP6")) nomem(); strnum[fmt_ulong(strnum,portlocal)] = 0; if (!pathexec_env("TCPLOCALPORT",strnum)) nomem(); if (fakev4) ipstr[ip4_fmt(ipstr,iplocal+12)] = 0; else ipstr[ip6_fmt(ipstr,iplocal)] = 0; if (!pathexec_env("TCPLOCALIP",ipstr)) nomem(); x = forcelocal; if (!x) if (dns_name6(&tmp,iplocal) == 0) { if (!stralloc_0(&tmp)) nomem(); x = tmp.s; } if (!pathexec_env("TCPLOCALHOST",x)) nomem(); if (socket_remote6(s,ipremote,&portremote,&netif) == -1) strerr_die2sys(111,FATAL,"unable to get remote address: "); strnum[fmt_ulong(strnum,portremote)] = 0; if (!pathexec_env("TCPREMOTEPORT",strnum)) nomem(); if (fakev4) ipstr[ip4_fmt(ipstr,ipremote+12)] = 0; else ipstr[ip6_fmt(ipstr,ipremote)] = 0; if (!pathexec_env("TCPREMOTEIP",ipstr)) nomem(); if (verbosity >= 2) strerr_warn4("tcpclient: connected to ",ipstr," port ",strnum,0); x = 0; if (flagremotehost) if (dns_name6(&tmp,ipremote) == 0) { if (!stralloc_0(&tmp)) nomem(); x = tmp.s; } if (!pathexec_env("TCPREMOTEHOST",x)) nomem(); x = 0; if (flagremoteinfo) if (remoteinfo6(&tmp,ipremote,portremote,iplocal,portlocal,itimeout,netif) == 0) { if (!stralloc_0(&tmp)) nomem(); x = tmp.s; } if (!pathexec_env("TCPREMOTEINFO",x)) nomem(); if (fd_move(6,s) == -1) strerr_die2sys(111,FATAL,"unable to set up descriptor 6: "); if (fd_copy(7,6) == -1) strerr_die2sys(111,FATAL,"unable to set up descriptor 7: "); sig_uncatch(sig_pipe); pathexec(argv); strerr_die4sys(111,FATAL,"unable to run ",*argv,": "); }
int main(int argc,char **argv) { char *hostname; // char *portname; int opt; struct servent *se; char *x; unsigned long u; int s; int t; while ((opt = getopt(argc,argv,"4dDvqQhHrR1UXx:t:u:g:l:b:B:c:I:pPoO")) != opteof) switch(opt) { case 'b': scan_ulong(optarg,&backlog); break; case 'c': scan_ulong(optarg,&limit); break; case 'X': flagallownorules = 1; break; case 'x': fnrules = optarg; break; case 'B': banner = optarg; break; case 'd': flagdelay = 1; break; case 'D': flagdelay = 0; break; case 'v': verbosity = 2; break; case 'q': verbosity = 0; break; case 'Q': verbosity = 1; break; case 'P': flagparanoid = 0; break; case 'p': flagparanoid = 1; break; case 'O': flagkillopts = 1; break; case 'o': flagkillopts = 0; break; case 'H': flagremotehost = 0; break; case 'h': flagremotehost = 1; break; // case 'R': flagremoteinfo = 0; break; case 'r': flagremoteinfo = 1; break; case 't': scan_ulong(optarg,&timeout); break; case 'U': x = env_get("UID"); if (x) scan_ulong(x,&uid); x = env_get("GID"); if (x) scan_ulong(x,&gid); break; case 'u': scan_ulong(optarg,&uid); break; case 'g': scan_ulong(optarg,&gid); break; case 'I': netif=socket_getifidx(optarg); break; case '1': flag1 = 1; break; // case '4': noipv6 = 1; break; case '4': ipv4socket = 1; break; // case '6': forcev6 = 1; break; case 'l': localhost = optarg; break; default: usage(); } argc -= optind; argv += optind; if (!verbosity) buffer_2->fd = -1; hostname = *argv++; if (!hostname) usage(); if (str_equal(hostname,"")) hostname = "0"; x = *argv++; if (!x) usage(); if (!x[scan_ulong(x,&u)]) localport = u; else { se = getservbyname(x,"tcp"); if (!se) errint(EHARD,B("unable to figure out port number for ",x)); uint16_unpack_big((char*)&se->s_port,&localport); } if (!*argv) usage(); sig_block(sig_child); sig_catch(sig_child,sigchld); sig_catch(sig_term,sigterm); sig_ignore(sig_pipe); if (str_equal(hostname,"0")) { byte_zero(localip,sizeof localip); } else { if (!stralloc_copys(&tmp,hostname)) errmem; if (dns_ip6_qualify(&addresses,&fqdn,&tmp) == -1) errint(EHARD,B("temporarily unable to figure out IP address for ",hostname,": ")); if (addresses.len < 16) errint(EHARD,B("no IP address for ",hostname)); byte_copy(localip,16,addresses.s); if (ip6_isv4mapped(localip)) ipv4socket = 1; } s = socket_tcp(); if (s == -1) errint(EHARD,"unable to create socket: "); if (socket_bind_reuse(s,localip,localport,netif) == -1) errint(EHARD,"unable to bind: "); if (!ipv4socket) ipv4socket = ip6_isv4mapped(localip); if (socket_local(s,localip,&localport,&netif) == -1) errint(EHARD,"unable to get local address: "); if (socket_listen(s,backlog) == -1) errint(EHARD,"unable to listen: "); ndelay_off(s); if (gid) if (prot_gid(gid) == -1) errint(EHARD,"unable to set gid: "); if (uid) if (prot_uid(uid) == -1) errint(EHARD,"unable to set uid: "); localportstr[fmt_ulong(localportstr,localport)] = 0; if (flag1) { buffer_init(&b,write,1,bspace,sizeof bspace); buffer_puts(&b,localportstr); buffer_puts(&b,"\n"); buffer_flush(&b); } close(0); close(1); printstatus(); for (;;) { while (numchildren >= limit) sig_pause(); sig_unblock(sig_child); t = socket_accept(s,remoteip,&remoteport,&netif); sig_block(sig_child); if (t == -1) continue; ++numchildren; printstatus(); switch(fork()) { case 0: close(s); doit(t); if ((fd_move(0,t) == -1) || (fd_copy(1,0) == -1)) errint(EHARD,"unable to set up descriptors: "); sig_uncatch(sig_child); sig_unblock(sig_child); sig_uncatch(sig_term); sig_uncatch(sig_pipe); pathexec(argv); errint(EHARD,B("unable to run ",*argv,": ")); case -1: errlog(ESOFT,NOTICE,"unable to fork: "); --numchildren; printstatus(); } close(t); } }
void doit(int t) { int j; uint32 scope_id; if (ip6_isv4mapped(remoteip)) remoteipstr[ip4_fmt(remoteipstr,remoteip+12)] = 0; else remoteipstr[ip6_fmt(remoteipstr,remoteip)] = 0; if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; log(B("pid ",strnum," from ",remoteipstr,0)); } if (flagkillopts) socket_ipoptionskill(t); if (!flagdelay) socket_tcpnodelay(t); if (*banner) { buffer_init(&b,write,t,bspace,sizeof bspace); if (buffer_putsflush(&b,banner) == -1) errint(EHARD,"unable to print banner: "); } if (socket_local(t,localip,&localport,&scope_id) == -1) errint(EHARD,"unable to get local address: "); if (ip6_isv4mapped(localip)) localipstr[ip4_fmt(localipstr,localip+12)] = 0; else localipstr[ip6_fmt(localipstr,localip)] = 0; remoteportstr[fmt_ulong(remoteportstr,remoteport)] = 0; if (!localhost) if (dns_name(&localhostsa,localip) == 0) if (localhostsa.len) { if (!stralloc_0(&localhostsa)) errmem; localhost = localhostsa.s; } env("PROTO","TCP"); env("TCPLOCALIP",localipstr); env("TCPLOCALPORT",localportstr); env("TCPLOCALHOST",localhost); if (flagremotehost) if (dns_name(&remotehostsa,remoteip) == 0) if (remotehostsa.len) { if (flagparanoid) if (dns_ip6(&tmp,&remotehostsa) == 0) for (j = 0;j + 16 <= tmp.len;j += 16) if (byte_equal(remoteip,16,tmp.s + j)) { flagparanoid = 0; break; } if (!flagparanoid) { if (!stralloc_0(&remotehostsa)) errmem; remotehost = remotehostsa.s; } } env("TCPREMOTEIP",remoteipstr); env("TCPREMOTEPORT",remoteportstr); env("TCPREMOTEHOST",remotehost); if (flagremoteinfo) { if (remoteinfo6(&tcpremoteinfo,remoteip,remoteport,localip,localport,timeout,netif) == -1) flagremoteinfo = 0; if (!stralloc_0(&tcpremoteinfo)) errmem; } env("TCPREMOTEINFO",flagremoteinfo ? tcpremoteinfo.s : 0); if (fnrules) { int fdrules; fdrules = open_read(fnrules); if (fdrules == -1) { if (errno != error_noent) drop_rules(); if (!flagallownorules) drop_rules(); } else { char* temp; if (ip6_isv4mapped(remoteip)) temp=remoteipstr+7; else temp=remoteipstr; if (rules(found,fdrules,temp,remotehost,flagremoteinfo ? tcpremoteinfo.s : 0) == -1) drop_rules(); close(fdrules); // log(B("checking tcp rules for ",remotehost,": pass")); } } if (verbosity >= 2) { strnum[fmt_ulong(strnum,getpid())] = 0; if (!stralloc_copys(&tmp,"qmail-tcpsrv: ")) errmem; safecats(flagdeny ? "deny" : "ok"); cats(" "); safecats(strnum); cats(" "); if (localhost) safecats(localhost); cats(":"); safecats(localipstr); cats(":"); safecats(localportstr); cats(" "); if (remotehost) safecats(remotehost); cats(":"); safecats(remoteipstr); // cats(":<remote info>"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); if (flagremoteinfo) safecats(tcpremoteinfo.s); cats(":"); safecats(remoteportstr); cats("\n"); buffer_putflush(buffer_2,tmp.s,tmp.len); } if (flagdeny) _exit(100); }
int main() { char *x; unsigned int i, j, k; unsigned long cachesize; static stralloc sa = {0}; x = env_get("INTERFACE"); if (x) scan_ulong(x,&interface); x = env_get("IP"); if (!x) strerr_die2x(111,FATAL,"$IP not set"); if (!ip6_scan(x,myipincoming)) strerr_die3x(111,FATAL,"unable to parse IP address ",x); #if 0 /* if if IP is a mapped-IPv4 address, disable IPv6 functionality */ /* this is actually a bad idea */ if (ip6_isv4mapped(myipincoming)) noipv6 = 1; #endif udp53 = socket_udp6(); if (udp53 == -1) strerr_die2sys(111,FATAL,"unable to create UDP socket: "); if (socket_bind6_reuse(udp53,myipincoming,53,interface) == -1) strerr_die2sys(111,FATAL,"unable to bind UDP socket: "); tcp53 = socket_tcp6(); if (tcp53 == -1) strerr_die2sys(111,FATAL,"unable to create TCP socket: "); if (socket_bind6_reuse(tcp53,myipincoming,53,interface) == -1) strerr_die2sys(111,FATAL,"unable to bind TCP socket: "); droproot(FATAL); socket_tryreservein(udp53,131072); byte_zero(seed,sizeof seed); read(0,seed,sizeof seed); dns_random_init(seed); close(0); x = env_get("IPSEND"); if (!x) strerr_die2x(111,FATAL,"$IPSEND not set"); if (!ip6_scan(x,myipoutgoing)) strerr_die3x(111,FATAL,"unable to parse IP address ",x); x = env_get("CACHESIZE"); if (!x) strerr_die2x(111,FATAL,"$CACHESIZE not set"); scan_ulong(x,&cachesize); if (!cache_init(cachesize)) strerr_die3x(111,FATAL,"not enough memory for cache of size ",x); if (openreadclose("ignoreip",&sa,64) < 0) strerr_die2x(111,FATAL,"trouble reading ignoreip"); for(j = k = i = 0; i < sa.len; i++) if (sa.s[i] == '\n') { sa.s[i] = '\0'; if (!stralloc_readyplus(&ignoreip,16)) strerr_die2x(111,FATAL,"out of memory parsing ignoreip"); if (!ip6_scan(sa.s+k,ignoreip.s+j)) strerr_die3x(111,FATAL,"unable to parse address in ignoreip ",ignoreip.s+k); j += 16; k = i + 1; } ignoreip.len = j; if (env_get("HIDETTL")) response_hidettl(); if (env_get("FORWARDONLY")) query_forwardonly(); if (!roots_init()) strerr_die2sys(111,FATAL,"unable to read servers: "); if (socket_listen(tcp53,20) == -1) strerr_die2sys(111,FATAL,"unable to listen on TCP socket: "); log_startup(); doit(); }
static ssize_t http_handle_announce( const int64 sock, struct ot_workstruct *ws, char *read_ptr ) { int numwant, tmp, scanon; unsigned short port = 0; char *write_ptr; ssize_t len; struct http_data *cookie = io_getcookie( sock ); /* This is to hack around stupid clients that send "announce ?info_hash" */ if( read_ptr[-1] != '?' ) { while( ( *read_ptr != '?' ) && ( *read_ptr != '\n' ) ) ++read_ptr; if( *read_ptr == '\n' ) HTTPERROR_400_PARAM; ++read_ptr; } #ifdef WANT_IP_FROM_PROXY if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_PROXY ) ) { ot_ip6 proxied_ip; char *fwd = http_header( ws->request, ws->header_size, "x-forwarded-for" ); if( fwd && scan_ip6( fwd, proxied_ip ) ) OT_SETIP( &ws->peer, proxied_ip ); else OT_SETIP( &ws->peer, cookie->ip ); } else #endif OT_SETIP( &ws->peer, cookie->ip ); ws->peer_id = NULL; ws->hash = NULL; OT_SETPORT( &ws->peer, &port ); OT_PEERFLAG( &ws->peer ) = 0; numwant = 50; scanon = 1; while( scanon ) { switch( scan_find_keywords(keywords_announce, &read_ptr, SCAN_SEARCHPATH_PARAM ) ) { case -2: scanon = 0; break; /* TERMINATOR */ case -1: HTTPERROR_400_PARAM; /* PARSE ERROR */ case -3: scan_urlencoded_skipvalue( &read_ptr ); break; case 1: /* matched "port" */ len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) || ( tmp > 0xffff ) ) HTTPERROR_400_PARAM; port = htons( tmp ); OT_SETPORT( &ws->peer, &port ); break; case 2: /* matched "left" */ if( ( len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) ) <= 0 ) HTTPERROR_400_PARAM; if( scan_fixed_int( write_ptr, len, &tmp ) ) tmp = 0; if( !tmp ) OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_SEEDING; break; case 3: /* matched "event" */ switch( scan_find_keywords( keywords_announce_event, &read_ptr, SCAN_SEARCHPATH_VALUE ) ) { case -1: HTTPERROR_400_PARAM; case 1: /* matched "completed" */ OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_COMPLETED; break; case 2: /* matched "stopped" */ OT_PEERFLAG( &ws->peer ) |= PEER_FLAG_STOPPED; break; default: break; } break; case 4: /* matched "numwant" */ len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &numwant ) ) HTTPERROR_400_PARAM; if( numwant < 0 ) numwant = 50; if( numwant > 200 ) numwant = 200; break; case 5: /* matched "compact" */ len = scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ); if( ( len <= 0 ) || scan_fixed_int( write_ptr, len, &tmp ) ) HTTPERROR_400_PARAM; if( !tmp ) HTTPERROR_400_COMPACT; break; case 6: /* matched "info_hash" */ if( ws->hash ) HTTPERROR_400_DOUBLEHASH; /* ignore this, when we have less than 20 bytes */ if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; ws->hash = (ot_hash*)write_ptr; break; #ifdef WANT_IP_FROM_QUERY_STRING case 7: /* matched "ip" */ { char *tmp_buf1 = ws->reply, *tmp_buf2 = ws->reply+16; len = scan_urlencoded_query( &read_ptr, tmp_buf2, SCAN_SEARCHPATH_VALUE ); tmp_buf2[len] = 0; if( ( len <= 0 ) || !scan_ip6( tmp_buf2, tmp_buf1 ) ) HTTPERROR_400_PARAM; OT_SETIP( &ws->peer, tmp_buf1 ); } break; #endif #ifdef WANT_FULLLOG_NETWORKS case 8: /* matched "lognet" */ { //if( accesslist_isblessed( cookie->ip, OT_PERMISSION_MAY_STAT ) ) { char *tmp_buf = ws->reply; ot_net net; signed short parsed, bits; len = scan_urlencoded_query( &read_ptr, tmp_buf, SCAN_SEARCHPATH_VALUE ); tmp_buf[len] = 0; if( len <= 0 ) HTTPERROR_400_PARAM; if( *tmp_buf == '-' ) { loglist_reset( ); return ws->reply_size = sprintf( ws->reply, "Successfully removed.\n" ); } parsed = scan_ip6( tmp_buf, net.address ); if( !parsed ) HTTPERROR_400_PARAM; if( tmp_buf[parsed++] != '/' ) bits = 128; else { parsed = scan_short( tmp_buf + parsed, &bits ); if( !parsed ) HTTPERROR_400_PARAM; if( ip6_isv4mapped( net.address ) ) bits += 96; } net.bits = bits; loglist_add_network( &net ); return ws->reply_size = sprintf( ws->reply, "Successfully added.\n" ); //} } #endif break; case 9: /* matched "peer_id" */ /* ignore this, when we have less than 20 bytes */ if( scan_urlencoded_query( &read_ptr, write_ptr = read_ptr, SCAN_SEARCHPATH_VALUE ) != 20 ) HTTPERROR_400_PARAM; ws->peer_id = write_ptr; break; } } #ifdef WANT_LOG_NUMWANT numwants[numwant]++; #endif /* XXX DEBUG stats_issue_event( EVENT_ACCEPT, FLAG_TCP, (uintptr_t)ws->reply ); */ /* Scanned whole query string */ if( !ws->hash ) return ws->reply_size = sprintf( ws->reply, "d14:failure reason80:Your client forgot to send your torrent's info_hash. Please upgrade your client.e" ); if( OT_PEERFLAG( &ws->peer ) & PEER_FLAG_STOPPED ) ws->reply_size = remove_peer_from_torrent( FLAG_TCP, ws ); else ws->reply_size = add_peer_to_torrent_and_return_peers( FLAG_TCP, ws, numwant ); stats_issue_event( EVENT_ANNOUNCE, FLAG_TCP, ws->reply_size); return ws->reply_size; }