1 /*
2 Copyright (c) 2007, 2008 by Juliusz Chroboczek
3 
4 Permission is hereby granted, free of charge, to any person obtaining a copy
5 of this software and associated documentation files (the "Software"), to deal
6 in the Software without restriction, including without limitation the rights
7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 copies of the Software, and to permit persons to whom the Software is
9 furnished to do so, subject to the following conditions:
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 THE SOFTWARE.
21 */
22 
23 #include <unistd.h>
24 #include <stdio.h>
25 #include <fcntl.h>
26 #include <string.h>
27 #include <sys/ioctl.h>
28 #include <sys/types.h>
29 #include <sys/uio.h>
30 #include <sys/socket.h>
31 #include <sys/un.h>
32 #include <netinet/in.h>
33 #include <netinet/in_systm.h>
34 #include <netinet/ip.h>
35 #include <arpa/inet.h>
36 #include <errno.h>
37 
38 #include "babeld.h"
39 #include "util.h"
40 #include "net.h"
41 
42 int
babel_socket(int port)43 babel_socket(int port)
44 {
45     struct sockaddr_in6 sin6;
46     int s, rc;
47     int saved_errno;
48     int one = 1, zero = 0;
49     const int ds = 0xc0;        /* CS6 - Network Control */
50 
51     s = socket(PF_INET6, SOCK_DGRAM, 0);
52     if(s < 0)
53         return -1;
54 
55     rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
56     if(rc < 0)
57         goto fail;
58 
59     rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
60     if(rc < 0)
61         goto fail;
62 
63     rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
64                     &zero, sizeof(zero));
65     if(rc < 0)
66         goto fail;
67 
68     rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
69                     &one, sizeof(one));
70     if(rc < 0)
71         goto fail;
72 
73     rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
74                     &one, sizeof(one));
75     if(rc < 0)
76         goto fail;
77 
78 #ifdef IPV6_TCLASS
79     rc = setsockopt(s, IPPROTO_IPV6, IPV6_TCLASS, &ds, sizeof(ds));
80 #else
81     rc = -1;
82     errno = ENOSYS;
83 #endif
84     if(rc < 0)
85         perror("Couldn't set traffic class");
86 
87     rc = fcntl(s, F_GETFL, 0);
88     if(rc < 0)
89         goto fail;
90 
91     rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
92     if(rc < 0)
93         goto fail;
94 
95     rc = fcntl(s, F_GETFD, 0);
96     if(rc < 0)
97         goto fail;
98 
99     rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
100     if(rc < 0)
101         goto fail;
102 
103     memset(&sin6, 0, sizeof(sin6));
104     sin6.sin6_family = AF_INET6;
105     sin6.sin6_port = htons(port);
106     rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
107     if(rc < 0)
108         goto fail;
109 
110     return s;
111 
112  fail:
113     saved_errno = errno;
114     close(s);
115     errno = saved_errno;
116     return -1;
117 }
118 
119 int
babel_recv(int s,void * buf,int buflen,struct sockaddr * sin,int slen)120 babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen)
121 {
122     struct iovec iovec;
123     struct msghdr msg;
124     int rc;
125 
126     memset(&msg, 0, sizeof(msg));
127     iovec.iov_base = buf;
128     iovec.iov_len = buflen;
129     msg.msg_name = sin;
130     msg.msg_namelen = slen;
131     msg.msg_iov = &iovec;
132     msg.msg_iovlen = 1;
133 
134     rc = recvmsg(s, &msg, 0);
135     return rc;
136 }
137 
138 int
babel_send(int s,const void * buf1,int buflen1,const void * buf2,int buflen2,const struct sockaddr * sin,int slen)139 babel_send(int s,
140            const void *buf1, int buflen1, const void *buf2, int buflen2,
141            const struct sockaddr *sin, int slen)
142 {
143     struct iovec iovec[2];
144     struct msghdr msg;
145     int rc, count = 0;
146 
147     iovec[0].iov_base = (void*)buf1;
148     iovec[0].iov_len = buflen1;
149     iovec[1].iov_base = (void*)buf2;
150     iovec[1].iov_len = buflen2;
151     memset(&msg, 0, sizeof(msg));
152     msg.msg_name = (struct sockaddr*)sin;
153     msg.msg_namelen = slen;
154     msg.msg_iov = iovec;
155     msg.msg_iovlen = 2;
156 
157     /* The Linux kernel can apparently keep returning EAGAIN indefinitely. */
158 
159  again:
160     rc = sendmsg(s, &msg, 0);
161     if(rc < 0) {
162         if(errno == EINTR) {
163             count++;
164             if(count < 100)
165                 goto again;
166         } else if(errno == EAGAIN) {
167             int rc2;
168             rc2 = wait_for_fd(1, s, 5);
169             if(rc2 > 0) {
170                 count++;
171                 if(count < 100)
172                     goto again;
173             }
174             errno = EAGAIN;
175         }
176     }
177     return rc;
178 }
179 
180 int
tcp_server_socket(int port,int local)181 tcp_server_socket(int port, int local)
182 {
183     struct sockaddr_in6 sin6;
184     int s, rc, saved_errno;
185     int one = 1;
186 
187     s = socket(PF_INET6, SOCK_STREAM, 0);
188     if(s < 0)
189         return -1;
190 
191     rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
192     if(rc < 0)
193         goto fail;
194 
195     rc = fcntl(s, F_GETFL, 0);
196     if(rc < 0)
197         goto fail;
198 
199     rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
200     if(rc < 0)
201         goto fail;
202 
203     rc = fcntl(s, F_GETFD, 0);
204     if(rc < 0)
205         goto fail;
206 
207     rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
208     if(rc < 0)
209         goto fail;
210 
211     memset(&sin6, 0, sizeof(sin6));
212     sin6.sin6_family = AF_INET6;
213     sin6.sin6_port = htons(port);
214     if(local) {
215         rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr);
216         if(rc < 0)
217             goto fail;
218     }
219     rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
220     if(rc < 0)
221         goto fail;
222 
223     rc = listen(s, 2);
224     if(rc < 0)
225         goto fail;
226 
227     return s;
228 
229  fail:
230     saved_errno = errno;
231     close(s);
232     errno = saved_errno;
233     return -1;
234 }
235 
236 int
unix_server_socket(const char * path)237 unix_server_socket(const char *path)
238 {
239     struct sockaddr_un sun;
240     int s, rc, saved_errno;
241 
242     if(strlen(path) >= sizeof(sun.sun_path))
243         return -1;
244 
245     s = socket(PF_UNIX, SOCK_STREAM, 0);
246     if(s < 0)
247         return -1;
248 
249     rc = fcntl(s, F_GETFL, 0);
250     if(rc < 0)
251         goto fail;
252 
253     rc = fcntl(s, F_SETFL, rc | O_NONBLOCK);
254     if(rc < 0)
255         goto fail;
256 
257     rc = fcntl(s, F_GETFD, 0);
258     if(rc < 0)
259         goto fail;
260 
261     rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
262     if(rc < 0)
263         goto fail;
264 
265     memset(&sun, 0, sizeof(sun));
266     sun.sun_family = AF_UNIX;
267     strncpy(sun.sun_path, path, sizeof(sun.sun_path));
268     rc = bind(s, (struct sockaddr *)&sun, sizeof(sun));
269     if(rc < 0)
270         goto fail;
271 
272     rc = listen(s, 2);
273     if(rc < 0)
274         goto fail_unlink;
275 
276     return s;
277 
278 fail_unlink:
279     saved_errno = errno;
280     unlink(path);
281     errno = saved_errno;
282 fail:
283     saved_errno = errno;
284     close(s);
285     errno = saved_errno;
286     return -1;
287 }
288