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