]> git.meshlink.io Git - catta/blob - socket.c
fix typo of prioq-test in the clean target of Makefile
[catta] / socket.c
1 #include <inttypes.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <stdio.h>
5 #include <sys/socket.h>
6 #include <netinet/in.h>
7 #include <arpa/inet.h>
8 #include <unistd.h>
9 #include <fcntl.h>
10 #include <sys/time.h>
11 #include <net/if.h>
12 #include <sys/ioctl.h>
13
14 #include "dns.h"
15 #include "util.h"
16
17 #define MDNS_PORT 5353
18
19 static void mdns_mcast_group_ipv4(struct sockaddr_in *ret_sa) {
20     g_assert(ret_sa);
21
22     memset(ret_sa, 0, sizeof(struct sockaddr_in));
23     
24     ret_sa->sin_family = AF_INET;
25     ret_sa->sin_port = htons(MDNS_PORT);
26     inet_pton(AF_INET, "224.0.0.251", &ret_sa->sin_addr);
27 }
28
29 static void mdns_mcast_group_ipv6(struct sockaddr_in6 *ret_sa) {
30
31     g_assert(ret_sa);
32
33     memset(ret_sa, 0, sizeof(struct sockaddr_in6));
34     
35     ret_sa->sin6_family = AF_INET6;
36     ret_sa->sin6_port = htons(MDNS_PORT);
37     inet_pton(AF_INET6, "ff02::fb", &ret_sa->sin6_addr);
38 }
39
40 int flx_mdns_mcast_join_ipv4 (int index, int fd)
41 {
42     struct ip_mreqn mreq; 
43     struct sockaddr_in sa;
44
45     mdns_mcast_group_ipv4 (&sa);
46  
47     memset(&mreq, 0, sizeof(mreq));
48     mreq.imr_multiaddr = sa.sin_addr;
49     mreq.imr_ifindex = index;
50  
51     if (setsockopt(fd, SOL_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
52         g_warning("IP_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
53         return -1;
54     } 
55
56     return 0;
57 }
58
59 int flx_mdns_mcast_join_ipv6 (int index, int fd)
60 {
61     struct ipv6_mreq mreq6; 
62     struct sockaddr_in6 sa6;
63
64     mdns_mcast_group_ipv6 (&sa6);
65
66     memset(&mreq6, 0, sizeof(mreq6));
67     mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
68     mreq6.ipv6mr_interface = index;
69
70     if (setsockopt(fd, SOL_IPV6, IPV6_ADD_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
71         g_warning("IPV6_ADD_MEMBERSHIP failed: %s\n", strerror(errno));
72         return -1;
73     }
74
75     return 0;
76 }
77
78 int flx_mdns_mcast_leave_ipv4 (int index, int fd)
79 {
80     struct ip_mreqn mreq; 
81     struct sockaddr_in sa;
82     
83     mdns_mcast_group_ipv4 (&sa);
84  
85     memset(&mreq, 0, sizeof(mreq));
86     mreq.imr_multiaddr = sa.sin_addr;
87     mreq.imr_ifindex = index;
88  
89     if (setsockopt(fd, SOL_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq)) < 0) {
90         g_warning("IP_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
91         return -1;
92     }
93
94     return 0;
95 }
96
97 int flx_mdns_mcast_leave_ipv6 (int index, int fd)
98 {
99     struct ipv6_mreq mreq6; 
100     struct sockaddr_in6 sa6;
101
102     mdns_mcast_group_ipv6 (&sa6);
103
104     memset(&mreq6, 0, sizeof(mreq6));
105     mreq6.ipv6mr_multiaddr = sa6.sin6_addr;
106     mreq6.ipv6mr_interface = index;
107
108     if (setsockopt(fd, SOL_IPV6, IPV6_DROP_MEMBERSHIP, &mreq6, sizeof(mreq6)) < 0) {
109         g_warning("IPV6_DROP_MEMBERSHIP failed: %s\n", strerror(errno));
110         return -1;
111     }
112
113     return 0;
114 }
115
116 gint flx_open_socket_ipv4(void) {
117     struct sockaddr_in sa, local;
118     int fd = -1, ttl, yes;
119         
120     if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
121         g_warning("socket() failed: %s\n", strerror(errno));
122         goto fail;
123     }
124     
125     ttl = 255;
126     if (setsockopt(fd, SOL_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)) < 0) {
127         g_warning("IP_MULTICAST_TTL failed: %s\n", strerror(errno));
128         goto fail;
129     }
130
131     ttl = 255;
132     if (setsockopt(fd, SOL_IP, IP_TTL, &ttl, sizeof(ttl)) < 0) {
133         g_warning("IP_TTL failed: %s\n", strerror(errno));
134         goto fail;
135     }
136     
137     yes = 1;
138     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
139         g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
140         goto fail;
141     }
142
143     yes = 1;
144     if (setsockopt(fd, SOL_IP, IP_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
145         g_warning("IP_MULTICAST_LOOP failed: %s\n", strerror(errno));
146         goto fail;
147     }
148
149     
150     memset(&local, 0, sizeof(local));
151     local.sin_family = AF_INET;
152     local.sin_port = htons(MDNS_PORT);
153     
154     if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
155         g_warning("bind() failed: %s\n", strerror(errno));
156         goto fail;
157     }
158
159     yes = 1;
160     if (setsockopt(fd, SOL_IP, IP_RECVTTL, &yes, sizeof(yes)) < 0) {
161         g_warning("IP_RECVTTL failed: %s\n", strerror(errno));
162         goto fail;
163     }
164
165     yes = 1;
166     if (setsockopt(fd, SOL_IP, IP_PKTINFO, &yes, sizeof(yes)) < 0) {
167         g_warning("IP_PKTINFO failed: %s\n", strerror(errno));
168         goto fail;
169     }
170     
171     if (flx_set_cloexec(fd) < 0) {
172         g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
173         goto fail;
174     }
175     
176     if (flx_set_nonblock(fd) < 0) {
177         g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
178         goto fail;
179     }
180
181     return fd;
182
183 fail:
184     if (fd >= 0)
185         close(fd);
186
187     return -1;
188 }
189
190 gint flx_open_socket_ipv6(void) {
191     struct sockaddr_in6 sa, local;
192     int fd = -1, ttl, yes;
193
194     mdns_mcast_group_ipv6(&sa);
195         
196     if ((fd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
197         g_warning("socket() failed: %s\n", strerror(errno));
198         goto fail;
199     }
200     
201     ttl = 255;
202     if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
203         g_warning("IPV6_MULTICAST_HOPS failed: %s\n", strerror(errno));
204         goto fail;
205     }
206
207     ttl = 255;
208     if (setsockopt(fd, SOL_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)) < 0) {
209         g_warning("IPV6_UNICAST_HOPS failed: %s\n", strerror(errno));
210         goto fail;
211     }
212     
213     yes = 1;
214     if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0) {
215         g_warning("SO_REUSEADDR failed: %s\n", strerror(errno));
216         goto fail;
217     }
218
219     yes = 1;
220     if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, &yes, sizeof(yes)) < 0) {
221         g_warning("IPV6_V6ONLY failed: %s\n", strerror(errno));
222         goto fail;
223     }
224
225     yes = 1;
226     if (setsockopt(fd, SOL_IPV6, IPV6_MULTICAST_LOOP, &yes, sizeof(yes)) < 0) {
227         g_warning("IPV6_MULTICAST_LOOP failed: %s\n", strerror(errno));
228         goto fail;
229     }
230
231     memset(&local, 0, sizeof(local));
232     local.sin6_family = AF_INET6;
233     local.sin6_port = htons(MDNS_PORT);
234     
235     if (bind(fd, (struct sockaddr*) &local, sizeof(local)) < 0) {
236         g_warning("bind() failed: %s\n", strerror(errno));
237         goto fail;
238     }
239
240     yes = 1;
241     if (setsockopt(fd, SOL_IPV6, IPV6_HOPLIMIT, &yes, sizeof(yes)) < 0) {
242         g_warning("IPV6_HOPLIMIT failed: %s\n", strerror(errno));
243         goto fail;
244     }
245
246     yes = 1;
247     if (setsockopt(fd, SOL_IPV6, IPV6_PKTINFO, &yes, sizeof(yes)) < 0) {
248         g_warning("IPV6_PKTINFO failed: %s\n", strerror(errno));
249         goto fail;
250     }
251     
252     if (flx_set_cloexec(fd) < 0) {
253         g_warning("FD_CLOEXEC failed: %s\n", strerror(errno));
254         goto fail;
255     }
256     
257     if (flx_set_nonblock(fd) < 0) {
258         g_warning("O_NONBLOCK failed: %s\n", strerror(errno));
259         goto fail;
260     }
261
262     return fd;
263
264 fail:
265     if (fd >= 0)
266         close(fd);
267
268     return -1;
269 }
270
271 static gint sendmsg_loop(gint fd, struct msghdr *msg, gint flags) {
272     g_assert(fd >= 0);
273     g_assert(msg);
274
275     for (;;) {
276     
277         if (sendmsg(fd, msg, flags) >= 0)
278             break;
279         
280         if (errno != EAGAIN) {
281             g_message("sendmsg() failed: %s\n", strerror(errno));
282             return -1;
283         }
284         
285         if (flx_wait_for_write(fd) < 0)
286             return -1;
287     }
288
289     return 0;
290 }
291
292 gint flx_send_dns_packet_ipv4(gint fd, gint interface, flxDnsPacket *p) {
293     struct sockaddr_in sa;
294     struct msghdr msg;
295     struct iovec io;
296     struct cmsghdr *cmsg;
297     struct in_pktinfo *pkti;
298     uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in_pktinfo)];
299     int i, n;
300
301     g_assert(fd >= 0);
302     g_assert(p);
303     g_assert(flx_dns_packet_check_valid(p) >= 0);
304
305     mdns_mcast_group_ipv4(&sa);
306
307     memset(&io, 0, sizeof(io));
308     io.iov_base = FLX_DNS_PACKET_DATA(p);
309     io.iov_len = p->size;
310
311     memset(cmsg_data, 0, sizeof(cmsg_data));
312     cmsg = (struct cmsghdr*) cmsg_data;
313     cmsg->cmsg_len = sizeof(cmsg_data);
314     cmsg->cmsg_level = IPPROTO_IP;
315     cmsg->cmsg_type = IP_PKTINFO;
316
317     pkti = (struct in_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
318     pkti->ipi_ifindex = interface;
319     
320     memset(&msg, 0, sizeof(msg));
321     msg.msg_name = &sa;
322     msg.msg_namelen = sizeof(sa);
323     msg.msg_iov = &io;
324     msg.msg_iovlen = 1;
325     msg.msg_control = cmsg_data;
326     msg.msg_controllen = sizeof(cmsg_data);
327     msg.msg_flags = 0;
328
329     return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
330 }
331
332 gint flx_send_dns_packet_ipv6(gint fd, gint interface, flxDnsPacket *p) {
333     struct sockaddr_in6 sa;
334     struct msghdr msg;
335     struct iovec io;
336     struct cmsghdr *cmsg;
337     struct in6_pktinfo *pkti;
338     uint8_t cmsg_data[sizeof(struct cmsghdr) + sizeof(struct in6_pktinfo)];
339     int i, n;
340
341     g_assert(fd >= 0);
342     g_assert(p);
343     g_assert(flx_dns_packet_check_valid(p) >= 0);
344
345     mdns_mcast_group_ipv6(&sa);
346
347     memset(&io, 0, sizeof(io));
348     io.iov_base = FLX_DNS_PACKET_DATA(p);
349     io.iov_len = p->size;
350
351     memset(cmsg_data, 0, sizeof(cmsg_data));
352     cmsg = (struct cmsghdr*) cmsg_data;
353     cmsg->cmsg_len = sizeof(cmsg_data);
354     cmsg->cmsg_level = IPPROTO_IPV6;
355     cmsg->cmsg_type = IPV6_PKTINFO;
356
357     pkti = (struct in6_pktinfo*) (cmsg_data + sizeof(struct cmsghdr));
358     pkti->ipi6_ifindex = interface;
359     
360     memset(&msg, 0, sizeof(msg));
361     msg.msg_name = &sa;
362     msg.msg_namelen = sizeof(sa);
363     msg.msg_iov = &io;
364     msg.msg_iovlen = 1;
365     msg.msg_control = cmsg_data;
366     msg.msg_controllen = sizeof(cmsg_data);
367     msg.msg_flags = 0;
368
369     return sendmsg_loop(fd, &msg, MSG_DONTROUTE);
370 }
371
372 flxDnsPacket* flx_recv_dns_packet_ipv4(gint fd, struct sockaddr_in *ret_sa, gint *ret_iface, guint8* ret_ttl) {
373     flxDnsPacket *p= NULL;
374     struct msghdr msg;
375     struct iovec io;
376     uint8_t aux[64];
377     ssize_t l;
378     struct cmsghdr *cmsg;
379     gboolean found_ttl = FALSE, found_iface = FALSE;
380
381     g_assert(fd >= 0);
382     g_assert(ret_sa);
383     g_assert(ret_iface);
384     g_assert(ret_ttl);
385
386     p = flx_dns_packet_new(0);
387
388     io.iov_base = FLX_DNS_PACKET_DATA(p);
389     io.iov_len = p->max_size;
390     
391     memset(&msg, 0, sizeof(msg));
392     msg.msg_name = ret_sa;
393     msg.msg_namelen = sizeof(struct sockaddr_in);
394     msg.msg_iov = &io;
395     msg.msg_iovlen = 1;
396     msg.msg_control = aux;
397     msg.msg_controllen = sizeof(aux);
398     msg.msg_flags = 0;
399     
400     if ((l = recvmsg(fd, &msg, 0)) < 0)
401         goto fail;
402
403     p->size = (size_t) l;
404     
405     *ret_ttl = 0;
406         
407     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg,cmsg)) {
408         if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) {
409             *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
410             found_ttl = TRUE;
411         }
412             
413         if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_PKTINFO) {
414             *ret_iface = ((struct in_pktinfo*) CMSG_DATA(cmsg))->ipi_ifindex;
415             found_iface = TRUE;
416         }
417     }
418
419     g_assert(found_iface);
420     g_assert(found_ttl);
421
422     return p;
423
424 fail:
425     if (p)
426         flx_dns_packet_free(p);
427
428     return NULL;
429 }
430
431 flxDnsPacket* flx_recv_dns_packet_ipv6(gint fd, struct sockaddr_in6 *ret_sa, gint *ret_iface, guint8* ret_ttl) {
432     flxDnsPacket *p = NULL;
433     struct msghdr msg;
434     struct iovec io;
435     uint8_t aux[64];
436     ssize_t l;
437     struct cmsghdr *cmsg;
438     gboolean found_ttl = FALSE, found_iface = FALSE;
439
440     g_assert(fd >= 0);
441     g_assert(ret_sa);
442     g_assert(ret_iface);
443     g_assert(ret_ttl);
444
445     p = flx_dns_packet_new(0);
446
447     io.iov_base = FLX_DNS_PACKET_DATA(p);
448     io.iov_len = p->max_size;
449     
450     memset(&msg, 0, sizeof(msg));
451     msg.msg_name = ret_sa;
452     msg.msg_namelen = sizeof(struct sockaddr_in6);
453     msg.msg_iov = &io;
454     msg.msg_iovlen = 1;
455     msg.msg_control = aux;
456     msg.msg_controllen = sizeof(aux);
457     msg.msg_flags = 0;
458     
459     if ((l = recvmsg(fd, &msg, 0)) < 0)
460         goto fail;
461
462     p->size = (size_t) l;
463     
464     *ret_ttl = 0;
465
466     for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
467         if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT) {
468             *ret_ttl = *(uint8_t *) CMSG_DATA(cmsg);
469             found_ttl = TRUE;
470         }
471             
472         if (cmsg->cmsg_level == SOL_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) {
473             *ret_iface = ((struct in6_pktinfo*) CMSG_DATA(cmsg))->ipi6_ifindex;
474             found_iface = TRUE;
475         }
476     }
477
478     g_assert(found_iface);
479     g_assert(found_ttl);
480
481     return p;
482
483 fail:
484     if (p)
485         flx_dns_packet_free(p);
486
487     return NULL;
488 }
489