NOEXPORT void proxy_server(CLI *c) { SOCKADDR_UNION addr; socklen_t addrlen; char src_host[IP_LEN], dst_host[IP_LEN]; char src_port[PORT_LEN], dst_port[PORT_LEN], *proto; int err; addrlen=sizeof addr; if(getpeername(c->local_rfd.fd, &addr.sa, &addrlen)) { sockerror("getpeername"); longjmp(c->err, 1); } err=getnameinfo(&addr.sa, addr_len(&addr), src_host, IP_LEN, src_port, PORT_LEN, NI_NUMERICHOST|NI_NUMERICSERV); if(err) { s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err)); longjmp(c->err, 1); } addrlen=sizeof addr; if(getsockname(c->local_rfd.fd, &addr.sa, &addrlen)) { sockerror("getsockname"); longjmp(c->err, 1); } err=getnameinfo(&addr.sa, addr_len(&addr), dst_host, IP_LEN, dst_port, PORT_LEN, NI_NUMERICHOST|NI_NUMERICSERV); if(err) { s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err)); longjmp(c->err, 1); } switch(addr.sa.sa_family) { case AF_INET: proto="TCP4"; break; #ifdef USE_IPv6 case AF_INET6: proto="TCP6"; break; #endif default: /* AF_UNIX */ proto="UNKNOWN"; } fd_printf(c, c->remote_fd.fd, "PROXY %s %s %s %s %s", proto, src_host, dst_host, src_port, dst_port); }
int hostport2addrlist(SOCKADDR_LIST *addr_list, char *hostname, char *portname) { struct addrinfo hints, *res=NULL, *cur; int err; addr_list->cur=0; /* initialize round-robin counter */ memset(&hints, 0, sizeof hints); #if defined(USE_IPv6) || defined(USE_WIN32) hints.ai_family=PF_UNSPEC; #else hints.ai_family=PF_INET; #endif hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; do { err=getaddrinfo(hostname, portname, &hints, &res); if(err && res) freeaddrinfo(res); if(err==EAI_AGAIN) { s_log(LOG_DEBUG, "getaddrinfo: EAI_AGAIN received: retrying"); sleep(1); } } while(err==EAI_AGAIN); switch(err) { case 0: break; /* success */ case EAI_SERVICE: s_log(LOG_ERR, "Unknown TCP service '%s'", portname); return 0; /* error */ default: s_log(LOG_ERR, "Error resolving '%s': %s", hostname, s_gai_strerror(err)); return 0; /* error */ } /* copy the list of addresses */ for(cur=res; cur && addr_list->num<MAX_HOSTS; cur=cur->ai_next, addr_list->num++) { if(cur->ai_addrlen>sizeof(SOCKADDR_UNION)) { s_log(LOG_ERR, "INTERNAL ERROR: ai_addrlen value too big"); freeaddrinfo(res); return 0; /* no results */ } memcpy(&addr_list->addr[addr_list->num], cur->ai_addr, cur->ai_addrlen); } freeaddrinfo(res); return addr_list->num; /* ok - return the number of addresses */ }
char *s_ntop(SOCKADDR_UNION *addr, socklen_t addrlen) { int err; char *host, *port, *retval; if(addrlen==sizeof(u_short)) /* see UNIX(7) manual for details */ return str_dup("unnamed socket"); host=str_alloc(256); port=str_alloc(256); /* needs to be long enough for AF_UNIX path */ err=getnameinfo(&addr->sa, addrlen, host, 256, port, 256, NI_NUMERICHOST|NI_NUMERICSERV); if(err) { s_log(LOG_ERR, "getnameinfo: %s", s_gai_strerror(err)); retval=str_dup("unresolvable address"); } else retval=str_printf("%s:%s", host, port); str_free(host); str_free(port); return retval; }
int hostport2addrlist(SOCKADDR_LIST *addr_list, char *hostname, char *portname) { struct addrinfo hints, *res=NULL, *cur; int err; addr_list->cur=0; /* initialize round-robin counter */ memset(&hints, 0, sizeof(hints)); #if defined(USE_IPv6) || defined(USE_WIN32) hints.ai_family=PF_UNSPEC; #else hints.ai_family=PF_INET; #endif hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; err=getaddrinfo(hostname, portname, &hints, &res); if(err) { if(err == EAI_SERVICE) s_log(LOG_ERR, "Unknown TCP service '%s'", portname); else s_log(LOG_ERR, "Error resolving '%s': %s", hostname, s_gai_strerror(err)); if(res) freeaddrinfo(res); return 0; /* Error */ } /* copy the list of addresses */ cur=res; while(cur && addr_list->num<MAX_HOSTS) { if(cur->ai_addrlen>sizeof(SOCKADDR_UNION)) { s_log(LOG_ERR, "INTERNAL ERROR: ai_addrlen value too big"); freeaddrinfo(res); return 0; /* no results */ } memcpy(&addr_list->addr[addr_list->num], cur->ai_addr, cur->ai_addrlen); cur=cur->ai_next; addr_list->num++; } freeaddrinfo(res); return addr_list->num; /* ok - return the number of addresses */ }
unsigned hostport2addrlist(SOCKADDR_LIST *addr_list, char *host_name, char *port_name) { struct addrinfo hints, *res=NULL, *cur; int err, retry=0; memset(&hints, 0, sizeof hints); #if defined(USE_IPv6) || defined(USE_WIN32) hints.ai_family=AF_UNSPEC; #else hints.ai_family=AF_INET; #endif hints.ai_socktype=SOCK_STREAM; hints.ai_protocol=IPPROTO_TCP; hints.ai_flags=0; if(addr_list->passive) { hints.ai_family=AF_INET; /* first try IPv4 for passive requests */ hints.ai_flags|=AI_PASSIVE; } for(;;) { err=getaddrinfo(host_name, port_name, &hints, &res); if(!err) break; if(res) freeaddrinfo(res); if(err==EAI_AGAIN && ++retry<=3) { s_log(LOG_DEBUG, "getaddrinfo: EAI_AGAIN received: retrying"); sleep(1); continue; } #if defined(USE_IPv6) || defined(USE_WIN32) if(hints.ai_family==AF_INET) { hints.ai_family=AF_UNSPEC; continue; /* retry for non-IPv4 addresses */ } #endif break; } if(err==EAI_SERVICE) { s_log(LOG_ERR, "Unknown TCP service \"%s\"", port_name); return 0; /* error */ } if(err) { s_log(LOG_ERR, "Error resolving \"%s\": %s", host_name ? host_name : (addr_list->passive ? DEFAULT_ANY : DEFAULT_LOOPBACK), s_gai_strerror(err)); return 0; /* error */ } /* copy the list of addresses */ for(cur=res; cur; cur=cur->ai_next) { if(cur->ai_addrlen>(int)sizeof(SOCKADDR_UNION)) { s_log(LOG_ERR, "INTERNAL ERROR: ai_addrlen value too big"); freeaddrinfo(res); return 0; /* no results */ } addr_list->addr=str_realloc(addr_list->addr, (addr_list->num+1)*sizeof(SOCKADDR_UNION)); memcpy(&addr_list->addr[addr_list->num], cur->ai_addr, (size_t)cur->ai_addrlen); ++(addr_list->num); } freeaddrinfo(res); return addr_list->num; /* ok - return the number of addresses */ }