int h_connect(int so, const char *host, const char *port, BINKD_CONFIG *config, const char *proxy, const char *socks) { int ntlm = 0; #ifdef NTLM char *ntlmsp = NULL; #endif int i, n; struct addrinfo *ai, *aiHead, hints; int aiErr; char buf[1024], *pbuf; char *sp, *sauth; struct in_addr defaddr; /* setup hints for getaddrinfo */ memset((void *)&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (proxy[0]) { strncpy(buf, proxy, sizeof(buf)); buf[sizeof(buf)-1] = '\0'; if ((sp=strchr(buf, '/')) != NULL) *sp++ = '\0'; Log(4, "connected to proxy %s", buf); if(sp) { char *sp1; #ifdef NTLM if(strchr(sp, '/') != strrchr(sp, '/')) { ntlm = 1; ntlmsp = sp = strdup(sp); } else #endif { if((sp1=strchr(sp, '/'))!=NULL) sp1[0]=':'; sp1=malloc(strlen(sp)*4/3 + 4); sp1[enbase64(sp, strlen(sp), sp1)] = 0; sp = sp1; } } memset(buf, 0, sizeof(buf)); if (socks[0]) { char *sp1; strncpy(buf, socks, sizeof(buf)-6); if((sp1=strchr(buf, '/'))!=NULL) sp1[0]=0; if((sp1=strchr(buf, ':'))==NULL) strcat(buf, ":1080"); sp1=strdup(buf); i=snprintf(buf, sizeof(buf), "CONNECT %s HTTP/1.%d\r\n", sp1, ntlm); free(sp1); } else i=snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/1.%d\r\n", host, port, ntlm); if (sp) { #ifdef NTLM if (ntlm) { if (i<sizeof(buf)) i+=snprintf(buf+i, sizeof(buf)-i, "Connection: keep-alive\r\n"); if (i<sizeof(buf)) i+=snprintf(buf+i, sizeof(buf)-i, "Proxy-Authorization: NTLM "); if (i<sizeof(buf)) getNTLM1(sp, buf+i, sizeof(buf)-i); if (sizeof(buf)>strlen(buf)+3) strcat(buf, "\r\n"); i = strlen(buf); } else #endif { if (i<sizeof(buf)) i+=snprintf(buf+i, sizeof(buf)-i, "Proxy-Authorization: basic %s\r\n", sp); free(sp); } } if (sizeof(buf) > i+2) { buf[i++]='\r'; buf[i++]='\n'; } if (send(so, buf, i, 0) < 0) { Log(4, "Send to proxy error: %s", TCPERR()); SetTCPError(PR_ERROR); return 1; } Log(10, "sent proxy sockfd %d request: %s", so, buf); for(i=0; i<sizeof(buf)-1; i++) { struct timeval tv; fd_set fds; FD_ZERO(&fds); FD_SET(so, &fds); tv.tv_sec=config->nettimeout; tv.tv_usec=0; if ((n=select(so+1, &fds, NULL, NULL, config->nettimeout > 0 ? &tv : NULL)) < 1) { if (n<0) Log(4, "proxy error: %s", TCPERR()); else Log(4, "proxy timeout..."); SetTCPError(PR_ERROR); return 1; } if ((n=recv(so, buf+i, 1, 0)) < 1) { if (n<0) Log(2, "Proxy error: %s", TCPERR()); else Log(2, "Connection closed by proxy..."); SetTCPError(PR_ERROR); return 1; } buf[i+1]=0; if((i+2>=sizeof(buf))||((sp=strstr(buf, "\r\n\r\n"))!=NULL)||((sp=strstr(buf, "\n\n"))!=NULL)) { #ifdef NTLM if ((ntlm) && ((sp=strstr(buf, "uthenticate: NTLM "))!=NULL)) { char *sp1 = strstr(buf, "Content-Length: "); sp = strdup(sp+18); if (sp1) { int j=atoi(sp1+16); for(;j>0; j--) { if(recv(so, buf+i, 1, 0)<1) break; } } memset(buf, 0, sizeof(buf)); i=snprintf(buf, sizeof(buf), "CONNECT %s:%s HTTP/1.%d\r\nProxy-Authorization: NTLM ", host, port, ntlm); i = getNTLM2(ntlmsp, sp, buf + i, sizeof(buf) - i); free(sp); if (i) Log(2, "Invalid username/password/host/domain string (%s) %d", ntlmsp, i); free(ntlmsp); if(!i) { ntlm = 0; if (strlen(buf)+3<sizeof(buf)) strcat(buf, "\r\n\r\n"); send(so, buf, strlen(buf), 0); i=0; continue; } } #endif if((sp=strchr(buf, '\n'))!=NULL) { sp[0]=0; sp--; if(sp[0]=='\r') sp[0]=0; } if(strstr(buf, " 200 ")) break; Log(2, "Connection rejected by proxy (%s)", buf); SetTCPError(PR_ERROR); return 1; } } } if (socks[0]) { strncpy(buf, socks, sizeof(buf)); buf[sizeof(buf)-1] = '\0'; if ((sauth=strchr(buf, '/')) != NULL) *sauth++ = '\0'; Log(4, "connected to socks%c %s", sauth ? '5' : '4', buf); if (!sauth) /* SOCKS4 */ { /* SOCKS4 only support IPv4 and we need the IP address */ if ((aiErr=srv_getaddrinfo(host, port, &hints, &aiHead)) != 0) { Log(2, "getaddrinfo failed: %s (%d)", gai_strerror(aiErr), aiErr); SetTCPError(PR_ERROR); return 1; } } else /* SOCKS5 */ { if ((aiErr=getaddrinfo(NULL, port, &hints, &aiHead)) != 0) { Log(2, "getaddrinfo failed: %s (%d)", gai_strerror(aiErr), aiErr); return 1; } sauth=strdup(sauth); sp=strchr(sauth, '/'); buf[0]=5; buf[2]=0; if(!sauth[0]) { buf[1]=1; send(so, buf, 3, 0); } else { buf[1]=2; if(sp) buf[3]=2; else buf[3]=1; send(so, buf, 4, 0); } if ((recv(so, buf, 2, 0)!=2)||((buf[1])&&(buf[1]!=1)&&(buf[1]!=2))) { Log(1, "Auth. method not supported by socks5 server"); free(sauth); freeaddrinfo(aiHead); SetTCPError(PR_ERROR); return 1; } Log(6, "Socks5, Auth=%d", buf[1]); if (buf[1]==2) /* username/password method */ { buf[0]=1; if (!sp) i=strlen(sauth); else i=(sp-sauth); buf[1]=i; memcpy(buf+2, sauth, i); i+=2; if (!sp) buf[i++]=0; else { sp++; buf[i++]=strlen(sp); strcpy(buf+i, sp); i+=strlen(sp); } send(so, buf, i, 0); buf[0]=buf[1]=0; if ((recv(so, buf, 2, 0)<2)||(buf[1])) { Log(1, "Authentication failed (socks5 returns %02X%02X)", (unsigned char)buf[0], (unsigned char)buf[1]); free(sauth); freeaddrinfo(aiHead); SetTCPError(PR_ERROR); return 1; } } } for (ai = aiHead; ai != NULL; ai = ai->ai_next) { unsigned short portnum = ntohs(((struct sockaddr_in*)(ai->ai_addr))->sin_port); if (!sauth) /* SOCKS4 */ { buf[0]=4; buf[1]=1; lockhostsem(); Log (4, strcmp(port, config->oport) == 0 ? "trying %s..." : "trying %s:%u...", inet_ntoa(((struct sockaddr_in*)(ai->ai_addr))->sin_addr), portnum); releasehostsem(); buf[2]=(unsigned char)((portnum>>8)&0xFF); buf[3]=(unsigned char)(portnum&0xFF); memcpy(buf+4, &(((struct sockaddr_in*)(ai->ai_addr))->sin_addr), 4); buf[8]=0; send(so, buf, 9, 0); } else /* SOCKS5 */ { buf[0]=5; buf[1]=1; buf[2]=0; if (isdigit(host[0]) && (defaddr.s_addr = inet_addr (host)) != INADDR_NONE) { buf[3]=1; memcpy(buf+4, &defaddr, 4); pbuf = buf+8; } else { buf[3]=3; i = strlen(host); buf[4]=(unsigned char)i; memcpy(buf+5, host, i); pbuf = buf+5+i; } *pbuf++=(unsigned char)((portnum>>8)&0xFF); *pbuf++=(unsigned char)(portnum&0xFF); send(so, buf, pbuf-buf, 0); } for (i=0; i<sizeof(buf); i++) { struct timeval tv; fd_set fds; FD_ZERO(&fds); FD_SET(so, &fds); tv.tv_sec=config->nettimeout; tv.tv_usec=0; if ((n=select(so+1, &fds, NULL, NULL, config->nettimeout > 0 ? &tv : NULL)) < 1) { if (n<0) Log(4, "socks error: %s", TCPERR()); else Log(4, "socks timeout..."); if (sauth) free(sauth); freeaddrinfo(aiHead); SetTCPError(PR_ERROR); return 1; } if ((n=recv(so, buf+i, 1, 0))<1) { if (n<0) Log(2, "socks error: %s", TCPERR()); Log(2, "connection closed by socks server..."); if (sauth) free(sauth); freeaddrinfo(aiHead); SetTCPError(PR_ERROR); return 1; } if (!sauth && i>6) /* 8th byte received */ { if (buf[0]!=0) { Log(2, "Bad reply from socks server"); freeaddrinfo(aiHead); SetTCPError(PR_ERROR); return 1; } if (buf[1]!=90) { Log(2, "connection rejected by socks4 server (%d)", (unsigned char)buf[1]); SetTCPError(PR_ERROR); break; /* try next IP */ } else { freeaddrinfo(aiHead); return 0; } } else if (sauth && i>5) { if (buf[0]!=5) { Log(2, "Bad reply from socks server"); free(sauth); freeaddrinfo(aiHead); SetTCPError(PR_ERROR); return 1; } if ((buf[3]==1) && (i<9)) continue; if ((buf[3]==3) && (i<(6+(unsigned char)buf[4]))) continue; if ((buf[3]==4) && (i<21)) continue; free(sauth); freeaddrinfo(aiHead); if (!buf[1]) return 0; switch (buf[1]) { case 1: Log (2, "general SOCKS5 server failure"); break; case 2: Log (2, "connection not allowed by ruleset (socks5)"); break; case 3: Log (2, "Network unreachable (socks5)"); break; case 4: Log (2, "Host unreachable (socks5)"); break; case 5: Log (2, "Connection refused (socks5)"); break; case 6: Log (2, "TTL expired (socks5)"); break; case 7: Log (2, "Command not supported by socks5"); break; case 8: Log (2, "Address type not supported"); break; default: Log (2, "Unknown reply (0x%02X) from socks5 server", (unsigned char)buf[1]); } SetTCPError(PR_ERROR); return 1; } } }
static int call0 (FTN_NODE *node, BINKD_CONFIG *config) { int sockfd = INVALID_SOCKET; int sock_out; char szDestAddr[FTN_ADDR_SZ + 1]; int i, rc, pid = -1; char host[BINKD_FQDNLEN + 5 + 1]; /* current host/port */ char addrbuf[BINKD_FQDNLEN + 1]; char servbuf[MAXSERVNAME + 1]; char *hosts; char *port; char *dst_host = host; const char *save_err; #ifdef HTTPS int use_proxy; char *proxy, *socks; struct addrinfo *aiProxyHead; #endif struct addrinfo *ai, *aiNodeHead, *aiHead, hints; int aiErr; /* setup hints for getaddrinfo */ memset((void *)&hints, 0, sizeof(hints)); hints.ai_family = node->IP_afamily; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; #ifdef WITH_PERL hosts = xstrdup(node->hosts); #ifdef HTTPS proxy = xstrdup(config->proxy); socks = xstrdup(config->socks); #endif if (!perl_on_call(node, config, &hosts #ifdef HTTPS , &proxy, &socks #endif )) { Log(1, "call aborted by Perl on_call()"); return 0; } #else hosts = node->hosts; #ifdef HTTPS proxy = config->proxy; socks = config->socks; #endif #endif ftnaddress_to_str (szDestAddr, &node->fa); Log (2, "call to %s", szDestAddr); setproctitle ("call to %s", szDestAddr); #ifdef HTTPS use_proxy = (node->NP_flag != NP_ON) && (!node->pipe || !node->pipe[0]) && (proxy[0] || socks[0]); if (use_proxy) { char *sp, *sport; strncpy(host, proxy[0] ? proxy : socks, sizeof(host)); if ((sp=strchr(host, ':')) != NULL) { *sp++ = '\0'; sport = sp; if ((sp=strchr(sp, '/')) != NULL) *sp++ = '\0'; } else { if ((sp=strchr(host, '/')) != NULL) *sp++ = '\0'; sport = proxy[0] ? "squid" : "socks"; /* default port */ } /* resolve proxy host */ if ( (aiErr = srv_getaddrinfo(host, sport, &hints, &aiProxyHead)) != 0) { Log(2, "Port %s not found, try default %d", sp, proxy[0] ? 3128 : 1080); aiErr = getaddrinfo(host, proxy[0] ? "3128" : "1080", &hints, &aiProxyHead); } if (aiErr != 0) { Log(1, "%s host %s not found", proxy[0] ? "Proxy" : "Socks", host); #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif return 0; } } #endif for (i = 1; sockfd == INVALID_SOCKET && (rc = get_host_and_port (i, host, &port, hosts, &node->fa, config)) != -1; ++i) { if (rc == 0) { Log (1, "%s: %i: error parsing host list", hosts, i); continue; } pid = -1; if (node->pipe && node->pipe[0]) { char *cmdline = strdup(node->pipe); cmdline = ed(cmdline, "*H", host, NULL); cmdline = ed(cmdline, "*I", port, NULL); pid = run3(cmdline, &sock_out, &sockfd, NULL); free(cmdline); if (pid != -1) { Log (4, "connected"); add_socket(sock_out); break; } if (!binkd_exit) { Log (1, "connection to %s failed"); /* bad_try (&node->fa, "exec error", BAD_CALL, config); */ } sockfd = INVALID_SOCKET; continue; } #ifdef HTTPS if (use_proxy) aiHead = aiProxyHead; else /* don't resolve if proxy or socks specified */ #endif { aiErr = srv_getaddrinfo(host, port, &hints, &aiNodeHead); if (aiErr != 0) { bad_try(&node->fa, "Cannot getaddrinfo", BAD_CALL, config); continue; } aiHead = aiNodeHead; } /* Trying... */ for (ai = aiHead; ai != NULL && sockfd == INVALID_SOCKET; ai = ai->ai_next) { if ((sockfd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == INVALID_SOCKET) { Log (1, "socket: %s", TCPERR ()); /* as long as there are more addresses, try those */ if (ai != NULL) continue; else { #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif freeaddrinfo(aiHead); return 0; } } add_socket(sockfd); /* Was the socket created after close_sockets loop in exitfunc()? */ if (binkd_exit) { #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif freeaddrinfo(aiHead); return 0; } rc = getnameinfo(ai->ai_addr, ai->ai_addrlen, addrbuf, sizeof(addrbuf), servbuf, sizeof(servbuf), NI_NUMERICHOST | NI_NUMERICSERV); if (rc != 0) { Log (2, "Error in getnameinfo(): %s (%d)", gai_strerror(rc), rc); snprintf(addrbuf, BINKD_FQDNLEN, "invalid"); *servbuf = '\0'; } #ifdef HTTPS if (use_proxy) { char *sp = strchr(host, ':'); if (sp) *sp = '\0'; if (port == config->oport) Log (4, "trying %s via %s %s:%s...", host, proxy[0] ? "proxy" : "socks", addrbuf, servbuf); else Log (4, "trying %s:%s via %s %s:%s...", host, port, proxy[0] ? "proxy" : "socks", addrbuf, servbuf); sprintf(host+strlen(host), ":%s", port); } else #endif { if (port == config->oport) Log (4, "trying %s [%s]...", host, addrbuf); else Log (4, "trying %s [%s]:%s...", host, addrbuf, servbuf); } /* find bind addr with matching address family */ if (config->bindaddr[0]) { struct addrinfo *src_ai, src_hints; memset((void *)&src_hints, 0, sizeof(src_hints)); src_hints.ai_socktype = SOCK_STREAM; src_hints.ai_family = ai->ai_family; src_hints.ai_protocol = IPPROTO_TCP; if ((aiErr = getaddrinfo(config->bindaddr, NULL, &src_hints, &src_ai)) == 0) { if (bind(sockfd, src_ai->ai_addr, src_ai->ai_addrlen)) Log(4, "bind: %s", TCPERR()); freeaddrinfo(src_ai); } else if (aiErr == EAI_FAMILY) /* address family of target and bind address don't match */ continue; else /* otherwise just warn and don't bind() */ Log(2, "bind -- getaddrinfo: %s (%d)", gai_strerror(aiErr), aiErr); } #ifdef HAVE_FORK if (config->connect_timeout) { signal(SIGALRM, alrm); alarm(config->connect_timeout); } #endif if (connect (sockfd, ai->ai_addr, ai->ai_addrlen) == 0) { #ifdef HAVE_FORK alarm(0); #endif Log (4, "connected"); sock_out = sockfd; dst_host = addrbuf; break; } #ifdef HAVE_FORK if (errno == EINTR && config->connect_timeout) save_err = strerror (ETIMEDOUT); else save_err = TCPERR (); alarm(0); #else save_err = TCPERR (); #endif if (!binkd_exit) { Log (1, "connection to %s failed: %s", szDestAddr, save_err); bad_try (&node->fa, save_err, BAD_CALL, config); } del_socket(sockfd); soclose (sockfd); sockfd = INVALID_SOCKET; } #ifdef HTTPS if (!use_proxy) #endif freeaddrinfo(aiNodeHead); #ifdef HTTPS if (sockfd != INVALID_SOCKET && use_proxy) { if (h_connect(sockfd, host, config, proxy, socks) != 0) { if (!binkd_exit) bad_try (&node->fa, TCPERR (), BAD_CALL, config); del_socket(sockfd); soclose (sockfd); sockfd = INVALID_SOCKET; } else if (port == config->oport) { char *pp; if( (pp = strchr(host, ':')) ){ *pp = '\0'; } } } #endif } #ifdef HTTPS if (use_proxy) freeaddrinfo(aiProxyHead); #endif #ifdef WITH_PERL xfree(hosts); #ifdef HTTPS xfree(proxy); xfree(socks); #endif #endif if (sockfd == INVALID_SOCKET) return 0; protocol (sockfd, sock_out, node, NULL, dst_host, config); if (pid != -1) { del_socket(sock_out); close(sock_out); #ifdef HAVE_WAITPID if (waitpid (pid, &rc, 0) == -1) { Log (1, "waitpid(%u) error: %s", pid, strerror(errno)); } else { if (WIFSIGNALED(rc)) Log (2, "process %u exited by signal %u", pid, WTERMSIG(rc)); else Log (4, "rc(%u)=%u", pid, WEXITSTATUS(rc)); } #endif close(sockfd); } else { del_socket(sockfd); soclose (sockfd); } return 1; }
int main (int argc, char *argv[]) #endif { char tmp[128]; #if defined(HAVE_FORK) char **saved_argv; mypid = getpid(); /* save argv as setproctitle() under some systems will change it */ saved_argv = mkargv (argc, argv); configpath = parseargs(argc, saved_argv); #else configpath = parseargs(argc, argv); #endif saved_envp = mkargv (-1, environ); #ifdef WIN32 if (service_flag==w32_installservice && !configpath) Log (0, "%s: invalid command line: config name must be specified", extract_filename(argv[0])); w32Init(); #ifdef BINKD9X { int win9x_rc; win9x_rc = win9x_process(argc, argv); if (win9x_rc != -1) return win9x_rc; } #endif #endif tzset(); if (poll_flag && server_flag) Log (0, "-p and -s cannot be used together"); #if defined(WIN32) && !defined(BINKD9X) if (service_flag!=w32_noservice) if (service(argc, argv, environ) && service_flag!=w32_run_as_service) { Log(0, "Windows NT service error"); } if (tray_flag) do_tray_flag(); else { atexit(UnloadBinkdIcon); LoadBinkdIcon(); } #endif /* No command line options: run both client and server */ if (!client_flag && !server_flag) client_flag = server_flag = 1; InitSem (&hostsem); InitSem (&resolvsem); InitSem (&lsem); InitSem (&blsem); InitSem (&varsem); InitSem (&config_sem); InitEventSem (&eothread); InitEventSem (&wakecmgr); #ifdef OS2 InitSem (&fhsem); #endif /* Init for ftnnode.c */ nodes_init (); if (configpath) { current_config = readcfg (configpath); if (!current_config) Log (0, "error in configuration, aborting"); if (dumpcfg_flag) { debug_readcfg (); exit(0); } InitLog(current_config->loglevel, current_config->conlog, current_config->logpath, current_config->nolog.first); } else if (verbose_flag) { #if defined(WIN32) && defined(BINKD9X) AllocTempConsole(); #endif printf ("Binkd " MYVER " (" __DATE__ " " __TIME__ "%s)\n", get_os_string ()); if (verbose_flag>1) { printf ("Compilation flags: " _DBNKD ".\n"); printf ("Facilities: " #ifndef srv_getaddrinfo "fsp1035 " #endif #ifndef HAVE_GETADDRINFO "rfc2553emu " #else "ipv6 " #endif "\n"); } exit (0); } else if (argc > 1) Log (0, "%s: invalid command line: config name must be specified", extract_filename(argv[0])); else usage (); print_args (tmp, sizeof (tmp), argv + 1); #ifdef WIN32 if (service_flag==w32_run_as_service) Log (4, "BEGIN service '%s', " MYNAME "/" MYVER "%s%s", service_name, get_os_string(), tmp); else Log (4, "BEGIN standalone, " MYNAME "/" MYVER "%s%s", get_os_string(), tmp); #else Log (4, "BEGIN, " MYNAME "/" MYVER "%s%s", get_os_string(), tmp); #endif if (sock_init ()) Log (0, "sock_init: %s", TCPERR ()); bsy_init (); rnd (); initsetproctitle (argc, argv, environ); #ifdef WIN32 SetFileApisToOEM(); #endif /* Set up break handler, set up exit list if needed */ if (!set_break_handlers ()) Log (0, "cannot install break handlers"); #if defined(SIGPIPE) signal(SIGPIPE, SIG_IGN); #endif #if defined(WITH_ZLIB) && defined(ZLIBDL) if (current_config->zlib_dll[0]) { if (!zlib_init(current_config->zlib_dll)) Log (2, "cannot load %s, GZ compression disabled", current_config->zlib_dll); else Log (6, "%s loaded successfully", current_config->zlib_dll); } else Log (current_config->zrules.first ? 3 : 5, "zlib-dll not defined, GZ compression disabled"); #endif #if defined(WITH_BZLIB2) && defined(ZLIBDL) if (current_config->bzlib2_dll[0]) { if (!bzlib2_init(current_config->bzlib2_dll)) Log (2, "cannot load %s, BZ2 compression disabled", current_config->bzlib2_dll); else Log (6, "%s loaded successfully", current_config->bzlib2_dll); } else Log (current_config->zrules.first #ifdef WITH_ZLIB && !zlib_loaded #endif ? 3 : 5, "bzlib2-dll not defined, BZ2 compression disabled"); #endif #ifdef WITH_PERL if (current_config->perl_script[0]) { if (!perl_init(current_config->perl_script, current_config)) { if (current_config->perl_strict) Log (0, "error parsing Perl script %s", current_config->perl_script); } else { perl_on_start(current_config); perl_config_loaded(current_config); } } #endif #ifdef HAVE_FORK signal (SIGCHLD, sighandler); #endif { /* Create polls and release polls list */ struct maskchain *psP; for (psP = psPolls.first; psP; psP = psP->next) poll_node (psP->mask, current_config); simplelist_free(&psPolls.linkpoint, destroy_maskchain); } if (no_flag) Log (0, "Exit on option '-n'"); if (inetd_flag) { FTN_ADDR ftn_addr, *pftn_addr; int tempfd; pftn_addr = NULL; if (remote_node) { if (parse_ftnaddress (remote_node, &ftn_addr, current_config->pDomains.first)) { char szFTNAddr[FTN_ADDR_SZ + 1]; exp_ftnaddress (&ftn_addr, current_config->pAddr, current_config->nAddr, current_config->pDomains.first); pftn_addr = &ftn_addr; ftnaddress_to_str (szFTNAddr, pftn_addr); Log (3, "Session with %s", szFTNAddr); } else Log (1, "`%s' cannot be parsed as a Fido-style address", remote_node); } if (!remote_addr) { char *p = getenv("SSH_CONNECTION"); if (p) { remote_addr = strdup(p); p = strchr(remote_addr, ' '); if (p) *p = '\0'; } } /* not using stdin/stdout itself to avoid possible collisions */ if (inetd_socket_in == -1) inetd_socket_in = dup(fileno(stdin)); if (inetd_socket_out == -1) inetd_socket_out = dup(fileno(stdout)); #ifdef UNIX tempfd = open("/dev/null", O_RDWR); #else tempfd = open("nul", O_RDWR); #endif if (tempfd != -1) { dup2(tempfd, fileno(stdin)); dup2(tempfd, fileno(stdout)); close(tempfd); } protocol (inetd_socket_in, inetd_socket_out, NULL, pftn_addr, remote_addr, current_config); soclose (inetd_socket_out); exit (0); } #ifdef BINKD_DAEMONIZE if (daemon_flag) { if (binkd_daemonize(1) < 0) Log (0, "Cannot daemonize"); else mypid = getpid(); } #endif #if defined(HAVE_FORK) signal (SIGHUP, sighandler); #endif if (client_flag && !server_flag) { clientmgr (0); exit (0); } pidsmgr = (int) getpid (); if (client_flag && (pidcmgr = branch (clientmgr, 0, 0)) < 0) { Log (0, "cannot branch out"); } if (*current_config->pid_file) { if ( unlink (current_config->pid_file) == 0 ) /* successfully unlinked, i.e. an old pid_file was found */ Log (1, "unexpected pid_file: %s: unlinked", current_config->pid_file); else { int current_log_level = 1; switch ( errno ) { case ENOENT : /* file not found or null pathname */ current_log_level = 8; /* it's ok */ break; default : break; } Log (current_log_level, "unlink_pid_file: %s: %s", current_config->pid_file, strerror (errno)); } create_sem_file (current_config->pid_file, 1); } servmgr (); return 0; }
static int do_server(BINKD_CONFIG *config) { struct addrinfo *ai, *aiHead, hints; int aiErr; SOCKET new_sockfd; int pid; socklen_t client_addr_len; struct sockaddr_storage client_addr; int opt = 1; int save_errno; struct listenchain *listen_list; /* setup hints for getaddrinfo */ memset((void *)&hints, 0, sizeof(hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; for (listen_list = config->listen.first; listen_list; listen_list = listen_list->next) { if ((aiErr = getaddrinfo(listen_list->addr[0] ? listen_list->addr : NULL, listen_list->port, &hints, &aiHead)) != 0) { Log(0, "servmgr getaddrinfo: %s (%d)", gai_strerror(aiErr), aiErr); return -1; } for (ai = aiHead; ai != NULL && sockfd_used < MAX_LISTENSOCK; ai = ai->ai_next) { sockfd[sockfd_used] = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sockfd[sockfd_used] < 0) { Log (0, "servmgr socket(): %s", TCPERR ()); continue; } #ifdef UNIX /* Not sure how to set NOINHERIT flag for socket on Windows and OS/2 */ if (fcntl(sockfd[sockfd_used], F_SETFD, FD_CLOEXEC) != 0) Log(1, "servmgr fcntl set FD_CLOEXEC error: %s", strerror(errno)); #endif #ifdef IPV6_V6ONLY if (ai->ai_family == PF_INET6) { int v6only = 1; if (setsockopt(sockfd[sockfd_used], IPPROTO_IPV6, IPV6_V6ONLY, (char *) &v6only, sizeof(v6only)) == SOCKET_ERROR) Log(1, "servmgr setsockopt (IPV6_V6ONLY): %s", TCPERR()); } #endif if (setsockopt (sockfd[sockfd_used], SOL_SOCKET, SO_REUSEADDR, (char *) &opt, sizeof opt) == SOCKET_ERROR) Log (1, "servmgr setsockopt (SO_REUSEADDR): %s", TCPERR ()); if (bind (sockfd[sockfd_used], ai->ai_addr, ai->ai_addrlen) != 0) { Log (0, "servmgr bind(): %s", TCPERR ()); soclose(sockfd[sockfd_used]); continue; } if (listen (sockfd[sockfd_used], 5) != 0) { Log(0, "servmgr listen(): %s", TCPERR ()); soclose(sockfd[sockfd_used]); continue; } sockfd_used++; } Log (3, "servmgr listen on %s:%s", listen_list->addr[0] ? listen_list->addr : "*", listen_list->port); freeaddrinfo(aiHead); } if (sockfd_used == 0) { Log(0, "servmgr: No listen socket open"); return -1; } setproctitle ("server manager (listen %s)", config->listen.first->port); for (;;) { struct timeval tv; int n; int curfd, maxfd = 0; fd_set r; FD_ZERO (&r); for (curfd=0; curfd<sockfd_used; curfd++) { FD_SET (sockfd[curfd], &r); if (sockfd[curfd] > maxfd) maxfd = sockfd[curfd]; } tv.tv_usec = 0; tv.tv_sec = CHECKCFG_INTERVAL; unblocksig(); check_child(&n_servers); n = select(maxfd+1, &r, NULL, NULL, &tv); blocksig(); switch (n) { case 0: /* timeout */ if (checkcfg()) { for (curfd=0; curfd<sockfd_used; curfd++) soclose(sockfd[curfd]); sockfd_used = 0; return 0; } unblocksig(); check_child(&n_servers); blocksig(); continue; case -1: save_errno = TCPERRNO; if (binkd_exit) goto accepterr; if (TCPERRNO == EINTR) { unblocksig(); check_child(&n_servers); blocksig(); if (checkcfg()) { for (curfd=0; curfd<sockfd_used; curfd++) soclose(sockfd[curfd]); sockfd_used = 0; return 0; } continue; } Log (1, "servmgr select(): %s", TCPERR ()); goto accepterr; } for (curfd=0; curfd<sockfd_used; curfd++) { if (!FD_ISSET(sockfd[curfd], &r)) continue; client_addr_len = sizeof (client_addr); if ((new_sockfd = accept (sockfd[curfd], (struct sockaddr *)&client_addr, &client_addr_len)) == INVALID_SOCKET) { save_errno = TCPERRNO; if (save_errno != EINVAL && save_errno != EINTR) { if (!binkd_exit) Log (1, "servmgr accept(): %s", TCPERR ()); #ifdef UNIX if (save_errno == ECONNRESET || save_errno == ETIMEDOUT || save_errno == ECONNABORTED || save_errno == EHOSTUNREACH) continue; #endif accepterr: #ifdef OS2 /* Buggy external process closed our socket? Or OS/2 bug? */ if (save_errno == ENOTSOCK) return 0; /* will force socket re-creation */ #endif return -1; } } else { char host[BINKD_FQDNLEN + 1]; char service[MAXSERVNAME + 1]; int aiErr; add_socket(new_sockfd); /* Was the socket created after close_sockets loop in exitfunc()? */ if (binkd_exit) { del_socket(new_sockfd); soclose(new_sockfd); continue; } rel_grow_handles (6); ext_rand=rand(); /* never resolve name in here, will be done during session */ aiErr = getnameinfo((struct sockaddr *)&client_addr, client_addr_len, host, sizeof(host), service, sizeof(service), NI_NUMERICHOST | NI_NUMERICSERV); if (aiErr == 0) Log (3, "incoming from %s (%s)", host, service); else { Log(2, "Error in getnameinfo(): %s (%d)", gai_strerror(aiErr), aiErr); Log(3, "incoming from unknown"); } /* Creating a new process for the incoming connection */ threadsafe(++n_servers); if ((pid = branch (serv, (void *) &new_sockfd, sizeof (new_sockfd))) < 0) { del_socket(new_sockfd); soclose(new_sockfd); rel_grow_handles (-6); threadsafe(--n_servers); PostSem(&eothread); Log (1, "servmgr branch(): cannot branch out"); sleep(1); } else { Log (5, "started server #%i, id=%i", n_servers, pid); #if defined(HAVE_FORK) && !defined(HAVE_THREADS) soclose (new_sockfd); #endif } } } } }