1109998Smarkm#include "tunala.h" 2109998Smarkm 3109998Smarkm#ifndef NO_IP 4109998Smarkm 5296465Sdelphij# define IP_LISTENER_BACKLOG 511/* So if it gets masked by 256 or some other 6296465Sdelphij * such value it'll still be respectable */ 7109998Smarkm 8109998Smarkm/* Any IP-related initialisations. For now, this means blocking SIGPIPE */ 9109998Smarkmint ip_initialise(void) 10109998Smarkm{ 11296465Sdelphij struct sigaction sa; 12109998Smarkm 13296465Sdelphij sa.sa_handler = SIG_IGN; 14296465Sdelphij sa.sa_flags = 0; 15296465Sdelphij sigemptyset(&sa.sa_mask); 16296465Sdelphij if (sigaction(SIGPIPE, &sa, NULL) != 0) 17296465Sdelphij return 0; 18296465Sdelphij return 1; 19109998Smarkm} 20109998Smarkm 21109998Smarkmint ip_create_listener_split(const char *ip, unsigned short port) 22109998Smarkm{ 23296465Sdelphij struct sockaddr_in in_addr; 24296465Sdelphij int fd = -1; 25296465Sdelphij int reuseVal = 1; 26109998Smarkm 27296465Sdelphij /* Create the socket */ 28296465Sdelphij if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 29296465Sdelphij goto err; 30296465Sdelphij /* Set the SO_REUSEADDR flag - servers act weird without it */ 31296465Sdelphij if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal), 32296465Sdelphij sizeof(reuseVal)) != 0) 33296465Sdelphij goto err; 34296465Sdelphij /* Prepare the listen address stuff */ 35296465Sdelphij in_addr.sin_family = AF_INET; 36296465Sdelphij memcpy(&in_addr.sin_addr.s_addr, ip, 4); 37296465Sdelphij in_addr.sin_port = htons(port); 38296465Sdelphij /* Bind to the required port/address/interface */ 39296465Sdelphij if (bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) != 40296465Sdelphij 0) 41296465Sdelphij goto err; 42296465Sdelphij /* Start "listening" */ 43296465Sdelphij if (listen(fd, IP_LISTENER_BACKLOG) != 0) 44296465Sdelphij goto err; 45296465Sdelphij return fd; 46296465Sdelphij err: 47296465Sdelphij if (fd != -1) 48296465Sdelphij close(fd); 49296465Sdelphij return -1; 50109998Smarkm} 51109998Smarkm 52109998Smarkmint ip_create_connection_split(const char *ip, unsigned short port) 53109998Smarkm{ 54296465Sdelphij struct sockaddr_in in_addr; 55296465Sdelphij int flags, fd = -1; 56109998Smarkm 57296465Sdelphij /* Create the socket */ 58296465Sdelphij if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1) 59296465Sdelphij goto err; 60296465Sdelphij /* Make it non-blocking */ 61296465Sdelphij if (((flags = fcntl(fd, F_GETFL, 0)) < 0) || 62296465Sdelphij (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)) 63296465Sdelphij goto err; 64296465Sdelphij /* Prepare the connection address stuff */ 65296465Sdelphij in_addr.sin_family = AF_INET; 66296465Sdelphij memcpy(&in_addr.sin_addr.s_addr, ip, 4); 67296465Sdelphij in_addr.sin_port = htons(port); 68296465Sdelphij /* Start a connect (non-blocking, in all likelihood) */ 69296465Sdelphij if ((connect(fd, (struct sockaddr *)&in_addr, 70296465Sdelphij sizeof(struct sockaddr_in)) != 0) && (errno != EINPROGRESS)) 71296465Sdelphij goto err; 72296465Sdelphij return fd; 73296465Sdelphij err: 74296465Sdelphij if (fd != -1) 75296465Sdelphij close(fd); 76296465Sdelphij return -1; 77109998Smarkm} 78109998Smarkm 79296465Sdelphijstatic char all_local_ip[] = { 0x00, 0x00, 0x00, 0x00 }; 80109998Smarkm 81109998Smarkmint ip_parse_address(const char *address, const char **parsed_ip, 82296465Sdelphij unsigned short *parsed_port, int accept_all_ip) 83109998Smarkm{ 84296465Sdelphij char buf[256]; 85296465Sdelphij struct hostent *lookup; 86296465Sdelphij unsigned long port; 87296465Sdelphij const char *ptr = strstr(address, ":"); 88296465Sdelphij const char *ip = all_local_ip; 89109998Smarkm 90296465Sdelphij if (!ptr) { 91296465Sdelphij /* 92296465Sdelphij * We assume we're listening on all local interfaces and have only 93296465Sdelphij * specified a port. 94296465Sdelphij */ 95296465Sdelphij if (!accept_all_ip) 96296465Sdelphij return 0; 97296465Sdelphij ptr = address; 98296465Sdelphij goto determine_port; 99296465Sdelphij } 100296465Sdelphij if ((ptr - address) > 255) 101296465Sdelphij return 0; 102296465Sdelphij memset(buf, 0, 256); 103296465Sdelphij memcpy(buf, address, ptr - address); 104296465Sdelphij ptr++; 105296465Sdelphij if ((lookup = gethostbyname(buf)) == NULL) { 106296465Sdelphij /* 107296465Sdelphij * Spit a message to differentiate between lookup failures and bad 108296465Sdelphij * strings. 109296465Sdelphij */ 110296465Sdelphij fprintf(stderr, "hostname lookup for '%s' failed\n", buf); 111296465Sdelphij return 0; 112296465Sdelphij } 113296465Sdelphij ip = lookup->h_addr_list[0]; 114296465Sdelphij determine_port: 115296465Sdelphij if (strlen(ptr) < 1) 116296465Sdelphij return 0; 117296465Sdelphij if (!int_strtoul(ptr, &port) || (port > 65535)) 118296465Sdelphij return 0; 119296465Sdelphij *parsed_ip = ip; 120296465Sdelphij *parsed_port = (unsigned short)port; 121296465Sdelphij return 1; 122109998Smarkm} 123109998Smarkm 124109998Smarkmint ip_create_listener(const char *address) 125109998Smarkm{ 126296465Sdelphij const char *ip; 127296465Sdelphij unsigned short port; 128109998Smarkm 129296465Sdelphij if (!ip_parse_address(address, &ip, &port, 1)) 130296465Sdelphij return -1; 131296465Sdelphij return ip_create_listener_split(ip, port); 132109998Smarkm} 133109998Smarkm 134109998Smarkmint ip_create_connection(const char *address) 135109998Smarkm{ 136296465Sdelphij const char *ip; 137296465Sdelphij unsigned short port; 138109998Smarkm 139296465Sdelphij if (!ip_parse_address(address, &ip, &port, 0)) 140296465Sdelphij return -1; 141296465Sdelphij return ip_create_connection_split(ip, port); 142109998Smarkm} 143109998Smarkm 144109998Smarkmint ip_accept_connection(int listen_fd) 145109998Smarkm{ 146296465Sdelphij return accept(listen_fd, NULL, NULL); 147109998Smarkm} 148109998Smarkm 149296465Sdelphij#endif /* !defined(NO_IP) */ 150