1 #include "tunala.h"
2
3 #ifndef NO_IP
4
5 # define IP_LISTENER_BACKLOG 511/* So if it gets masked by 256 or some other
6 * such value it'll still be respectable */
7
8 /* Any IP-related initialisations. For now, this means blocking SIGPIPE */
ip_initialise(void)9 int ip_initialise(void)
10 {
11 struct sigaction sa;
12
13 sa.sa_handler = SIG_IGN;
14 sa.sa_flags = 0;
15 sigemptyset(&sa.sa_mask);
16 if (sigaction(SIGPIPE, &sa, NULL) != 0)
17 return 0;
18 return 1;
19 }
20
ip_create_listener_split(const char * ip,unsigned short port)21 int ip_create_listener_split(const char *ip, unsigned short port)
22 {
23 struct sockaddr_in in_addr;
24 int fd = -1;
25 int reuseVal = 1;
26
27 /* Create the socket */
28 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
29 goto err;
30 /* Set the SO_REUSEADDR flag - servers act weird without it */
31 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)(&reuseVal),
32 sizeof(reuseVal)) != 0)
33 goto err;
34 /* Prepare the listen address stuff */
35 in_addr.sin_family = AF_INET;
36 memcpy(&in_addr.sin_addr.s_addr, ip, 4);
37 in_addr.sin_port = htons(port);
38 /* Bind to the required port/address/interface */
39 if (bind(fd, (struct sockaddr *)&in_addr, sizeof(struct sockaddr_in)) !=
40 0)
41 goto err;
42 /* Start "listening" */
43 if (listen(fd, IP_LISTENER_BACKLOG) != 0)
44 goto err;
45 return fd;
46 err:
47 if (fd != -1)
48 close(fd);
49 return -1;
50 }
51
ip_create_connection_split(const char * ip,unsigned short port)52 int ip_create_connection_split(const char *ip, unsigned short port)
53 {
54 struct sockaddr_in in_addr;
55 int flags, fd = -1;
56
57 /* Create the socket */
58 if ((fd = socket(PF_INET, SOCK_STREAM, 0)) == -1)
59 goto err;
60 /* Make it non-blocking */
61 if (((flags = fcntl(fd, F_GETFL, 0)) < 0) ||
62 (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0))
63 goto err;
64 /* Prepare the connection address stuff */
65 in_addr.sin_family = AF_INET;
66 memcpy(&in_addr.sin_addr.s_addr, ip, 4);
67 in_addr.sin_port = htons(port);
68 /* Start a connect (non-blocking, in all likelihood) */
69 if ((connect(fd, (struct sockaddr *)&in_addr,
70 sizeof(struct sockaddr_in)) != 0) && (errno != EINPROGRESS))
71 goto err;
72 return fd;
73 err:
74 if (fd != -1)
75 close(fd);
76 return -1;
77 }
78
79 static char all_local_ip[] = { 0x00, 0x00, 0x00, 0x00 };
80
ip_parse_address(const char * address,const char ** parsed_ip,unsigned short * parsed_port,int accept_all_ip)81 int ip_parse_address(const char *address, const char **parsed_ip,
82 unsigned short *parsed_port, int accept_all_ip)
83 {
84 char buf[256];
85 struct hostent *lookup;
86 unsigned long port;
87 const char *ptr = strstr(address, ":");
88 const char *ip = all_local_ip;
89
90 if (!ptr) {
91 /*
92 * We assume we're listening on all local interfaces and have only
93 * specified a port.
94 */
95 if (!accept_all_ip)
96 return 0;
97 ptr = address;
98 goto determine_port;
99 }
100 if ((ptr - address) > 255)
101 return 0;
102 memset(buf, 0, 256);
103 memcpy(buf, address, ptr - address);
104 ptr++;
105 if ((lookup = gethostbyname(buf)) == NULL) {
106 /*
107 * Spit a message to differentiate between lookup failures and bad
108 * strings.
109 */
110 fprintf(stderr, "hostname lookup for '%s' failed\n", buf);
111 return 0;
112 }
113 ip = lookup->h_addr_list[0];
114 determine_port:
115 if (strlen(ptr) < 1)
116 return 0;
117 if (!int_strtoul(ptr, &port) || (port > 65535))
118 return 0;
119 *parsed_ip = ip;
120 *parsed_port = (unsigned short)port;
121 return 1;
122 }
123
ip_create_listener(const char * address)124 int ip_create_listener(const char *address)
125 {
126 const char *ip;
127 unsigned short port;
128
129 if (!ip_parse_address(address, &ip, &port, 1))
130 return -1;
131 return ip_create_listener_split(ip, port);
132 }
133
ip_create_connection(const char * address)134 int ip_create_connection(const char *address)
135 {
136 const char *ip;
137 unsigned short port;
138
139 if (!ip_parse_address(address, &ip, &port, 0))
140 return -1;
141 return ip_create_connection_split(ip, port);
142 }
143
ip_accept_connection(int listen_fd)144 int ip_accept_connection(int listen_fd)
145 {
146 return accept(listen_fd, NULL, NULL);
147 }
148
149 #endif /* !defined(NO_IP) */
150