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