2 * Copyright (C) 2014 John Crispin <blogic@openwrt.org>
3 * Copyright (C) 2014 Felix Fietkau <nbd@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <sys/socket.h>
17 #include <sys/ioctl.h>
18 #include <sys/types.h>
20 #include <sys/utsname.h>
22 #include <netinet/in.h>
23 #include <arpa/inet.h>
31 #include <libubox/usock.h>
32 #include <libubox/uloop.h>
33 #include <libubox/avl-cmp.h>
34 #include <libubox/utils.h>
35 #include "interface.h"
41 interface_send_packet4(struct interface
*iface
, struct iovec
*iov
, int iov_len
)
43 static size_t cmsg_data
[( CMSG_SPACE(sizeof(struct in_pktinfo
)) / sizeof(size_t)) + 1];
44 static struct sockaddr_in a
;
45 static struct msghdr m
= {
46 .msg_name
= (struct sockaddr
*) &a
,
47 .msg_namelen
= sizeof(a
),
48 .msg_control
= cmsg_data
,
49 .msg_controllen
= CMSG_LEN(sizeof(struct in_pktinfo
)),
51 struct in_pktinfo
*pkti
;
53 int fd
= iface
->fd
.fd
;
55 a
.sin_family
= AF_INET
;
56 a
.sin_port
= htons(MCAST_PORT
);
58 m
.msg_iovlen
= iov_len
;
60 memset(cmsg_data
, 0, sizeof(cmsg_data
));
61 cmsg
= CMSG_FIRSTHDR(&m
);
62 cmsg
->cmsg_len
= m
.msg_controllen
;
63 cmsg
->cmsg_level
= IPPROTO_IP
;
64 cmsg
->cmsg_type
= IP_PKTINFO
;
66 pkti
= (struct in_pktinfo
*) CMSG_DATA(cmsg
);
67 pkti
->ipi_ifindex
= iface
->ifindex
;
69 a
.sin_addr
.s_addr
= inet_addr(MCAST_ADDR
);
71 return sendmsg(fd
, &m
, 0);
75 interface_send_packet6(struct interface
*iface
, struct iovec
*iov
, int iov_len
)
77 static size_t cmsg_data
[( CMSG_SPACE(sizeof(struct in6_pktinfo
)) / sizeof(size_t)) + 1];
78 static struct sockaddr_in6 a
;
79 static struct msghdr m
= {
80 .msg_name
= (struct sockaddr
*) &a
,
81 .msg_namelen
= sizeof(a
),
82 .msg_control
= cmsg_data
,
83 .msg_controllen
= CMSG_LEN(sizeof(struct in6_pktinfo
)),
85 struct in6_pktinfo
*pkti
;
87 int fd
= iface
->fd
.fd
;
89 a
.sin6_family
= AF_INET6
;
90 a
.sin6_port
= htons(MCAST_PORT
);
92 m
.msg_iovlen
= iov_len
;
94 memset(cmsg_data
, 0, sizeof(cmsg_data
));
95 cmsg
= CMSG_FIRSTHDR(&m
);
96 cmsg
->cmsg_len
= m
.msg_controllen
;
97 cmsg
->cmsg_level
= IPPROTO_IPV6
;
98 cmsg
->cmsg_type
= IPV6_PKTINFO
;
100 pkti
= (struct in6_pktinfo
*) CMSG_DATA(cmsg
);
101 pkti
->ipi6_ifindex
= iface
->ifindex
;
103 inet_pton(AF_INET6
, MCAST_ADDR6
, &a
.sin6_addr
);
105 return sendmsg(fd
, &m
, 0);
109 interface_send_packet(struct interface
*iface
, struct iovec
*iov
, int iov_len
)
112 return interface_send_packet6(iface
, iov
, iov_len
);
114 return interface_send_packet4(iface
, iov
, iov_len
);
117 static void interface_close(struct interface
*iface
)
119 if (iface
->fd
.fd
< 0)
122 announce_free(iface
);
123 uloop_fd_delete(&iface
->fd
);
128 static void interface_free(struct interface
*iface
)
130 interface_close(iface
);
135 read_socket(struct uloop_fd
*u
, unsigned int events
)
137 struct interface
*iface
= container_of(u
, struct interface
, fd
);
138 static uint8_t buffer
[8 * 1024];
140 char cmsg6
[CMSG_SPACE(sizeof(struct in6_pktinfo
))];
141 struct cmsghdr
*cmsgptr
;
144 struct sockaddr_in6 from
;
145 int flags
= 0, ifindex
= -1;
148 interface_close(iface
);
149 uloop_timeout_set(&iface
->reconnect
, 1000);
153 iov
[0].iov_base
= buffer
;
154 iov
[0].iov_len
= sizeof(buffer
);
156 memset(&msg
, 0, sizeof(msg
));
157 msg
.msg_name
= (struct sockaddr
*) &from
;
158 msg
.msg_namelen
= (iface
->v6
) ? (sizeof(struct sockaddr_in6
)) : (sizeof(struct sockaddr_in
));
161 msg
.msg_control
= &cmsg6
;
162 msg
.msg_controllen
= sizeof(cmsg6
);
164 len
= recvmsg(u
->fd
, &msg
, flags
);
166 perror("read failed");
169 for (cmsgptr
= CMSG_FIRSTHDR(&msg
); cmsgptr
!= NULL
&& ifindex
== -1; cmsgptr
= CMSG_NXTHDR(&msg
, cmsgptr
)) {
170 void *c
= CMSG_DATA(cmsgptr
);
172 if (cmsgptr
->cmsg_level
== IPPROTO_IP
&& cmsgptr
->cmsg_type
== IP_PKTINFO
)
173 ifindex
= ((struct in_pktinfo
*) c
)->ipi_ifindex
;
174 else if (cmsgptr
->cmsg_level
== IPPROTO_IPV6
&& cmsgptr
->cmsg_type
== IPV6_PKTINFO
)
175 ifindex
= ((struct in6_pktinfo
*) c
)->ipi6_ifindex
;
178 dns_handle_packet(iface
, buffer
, len
);
180 printf("%d\n", ifindex
);
184 interface_socket_setup4(struct interface
*iface
)
186 struct ip_mreqn mreq
;
190 struct sockaddr_in sa
= { 0 };
191 int fd
= iface
->fd
.fd
;
193 sa
.sin_family
= AF_INET
;
194 sa
.sin_port
= htons(MCAST_PORT
);
195 inet_pton(AF_INET
, MCAST_ADDR
, &sa
.sin_addr
);
197 memset(&mreq
, 0, sizeof(mreq
));
198 mreq
.imr_address
.s_addr
= iface
->v4_addr
.s_addr
;
199 mreq
.imr_multiaddr
= sa
.sin_addr
;
200 mreq
.imr_ifindex
= iface
->ifindex
;
202 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, &ttl
, sizeof(ttl
)) < 0)
203 fprintf(stderr
, "ioctl failed: IP_MULTICAST_TTL\n");
205 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) < 0)
206 fprintf(stderr
, "ioctl failed: SO_REUSEADDR\n");
208 /* Some network drivers have issues with dropping membership of
209 * mcast groups when the iface is down, but don't allow rejoining
210 * when it comes back up. This is an ugly workaround
211 * -- this was copied from avahi --
213 setsockopt(fd
, IPPROTO_IP
, IP_DROP_MEMBERSHIP
, &mreq
, sizeof(mreq
));
215 if (setsockopt(fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
)) < 0) {
216 fprintf(stderr
, "failed to join multicast group: %s\n", strerror(errno
));
222 if (setsockopt(fd
, IPPROTO_IP
, IP_RECVTTL
, &yes
, sizeof(yes
)) < 0)
223 fprintf(stderr
, "ioctl failed: IP_RECVTTL\n");
225 if (setsockopt(fd
, IPPROTO_IP
, IP_PKTINFO
, &yes
, sizeof(yes
)) < 0)
226 fprintf(stderr
, "ioctl failed: IP_PKTINFO\n");
228 if (setsockopt(fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, &no
, sizeof(no
)) < 0)
229 fprintf(stderr
, "ioctl failed: IP_MULTICAST_LOOP\n");
235 interface_socket_setup6(struct interface
*iface
)
237 struct ipv6_mreq mreq
;
241 struct sockaddr_in6 sa
= { 0 };
242 int fd
= iface
->fd
.fd
;
244 sa
.sin6_family
= AF_INET6
;
245 sa
.sin6_port
= htons(MCAST_PORT
);
246 inet_pton(AF_INET6
, MCAST_ADDR6
, &sa
.sin6_addr
);
248 memset(&mreq
, 0, sizeof(mreq
));
249 mreq
.ipv6mr_multiaddr
= sa
.sin6_addr
;
250 mreq
.ipv6mr_interface
= iface
->ifindex
;
252 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, &ttl
, sizeof(ttl
)) < 0)
253 fprintf(stderr
, "ioctl failed: IPV6_MULTICAST_HOPS\n");
255 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_UNICAST_HOPS
, &ttl
, sizeof(ttl
)) < 0)
256 fprintf(stderr
, "ioctl failed: IPV6_UNICAST_HOPS\n");
258 if (setsockopt(fd
, SOL_SOCKET
, SO_REUSEADDR
, &yes
, sizeof(yes
)) < 0)
259 fprintf(stderr
, "ioctl failed: SO_REUSEADDR\n");
261 setsockopt(fd
, IPPROTO_IPV6
, IPV6_LEAVE_GROUP
, &mreq
, sizeof(mreq
));
262 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_ADD_MEMBERSHIP
, &mreq
, sizeof(mreq
)) < 0) {
263 fprintf(stderr
, "failed to join multicast group: %s\n", strerror(errno
));
269 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVPKTINFO
, &yes
, sizeof(yes
)) < 0)
270 fprintf(stderr
, "ioctl failed: IPV6_RECVPKTINFO\n");
272 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_RECVHOPLIMIT
, &yes
, sizeof(yes
)) < 0)
273 fprintf(stderr
, "ioctl failed: IPV6_RECVHOPLIMIT\n");
275 if (setsockopt(fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, &no
, sizeof(no
)) < 0)
276 fprintf(stderr
, "ioctl failed: IPV6_MULTICAST_LOOP\n");
282 reconnect_socket(struct uloop_timeout
*timeout
)
284 struct interface
*iface
= container_of(timeout
, struct interface
, reconnect
);
289 snprintf(mcast_addr
, sizeof(mcast_addr
), "%s%%%s", iface
->mcast_addr
, iface
->name
);
290 type
= USOCK_IPV6ONLY
;
292 snprintf(mcast_addr
, sizeof(mcast_addr
), "%s", iface
->mcast_addr
);
293 type
= USOCK_IPV4ONLY
;
296 iface
->fd
.fd
= usock(USOCK_UDP
| USOCK_SERVER
| USOCK_NONBLOCK
| type
, mcast_addr
, "5353");
297 if (iface
->fd
.fd
< 0) {
298 fprintf(stderr
, "failed to add listener %s: %s\n", mcast_addr
, strerror(errno
));
302 if (!iface
->v6
&& interface_socket_setup4(iface
)) {
307 if (iface
->v6
&& interface_socket_setup6(iface
)) {
312 uloop_fd_add(&iface
->fd
, ULOOP_READ
);
313 dns_send_question(iface
, "_services._dns-sd._udp.local", TYPE_PTR
);
314 announce_init(iface
);
318 uloop_timeout_set(timeout
, 1000);
322 static void interface_start(struct interface
*iface
)
324 iface
->fd
.cb
= read_socket
;
325 iface
->reconnect
.cb
= reconnect_socket
;
326 uloop_timeout_set(&iface
->reconnect
, 100);
330 iface_update_cb(struct vlist_tree
*tree
, struct vlist_node
*node_new
,
331 struct vlist_node
*node_old
)
333 struct interface
*iface
;
336 iface
= container_of(node_old
, struct interface
, node
);
337 interface_free(iface
);
341 iface
= container_of(node_new
, struct interface
, node
);
342 interface_start(iface
);
347 get_iface_ipv4(struct interface
*iface
)
349 struct sockaddr_in
*sin
;
353 if (cfg_proto
&& (cfg_proto
!= 4))
356 sock
= socket(AF_INET
, SOCK_DGRAM
, 0);
360 memset(&ir
, 0, sizeof(struct ifreq
));
361 strncpy(ir
.ifr_name
, iface
->name
, sizeof(ir
.ifr_name
));
363 ret
= ioctl(sock
, SIOCGIFADDR
, &ir
);
367 sin
= (struct sockaddr_in
*) &ir
.ifr_addr
;
368 memcpy(&iface
->v4_addr
, &sin
->sin_addr
, sizeof(iface
->v4_addr
));
369 iface
->mcast_addr
= MCAST_ADDR
;
376 get_iface_ipv6(struct interface
*iface
)
378 struct sockaddr_in6 addr
= {AF_INET6
, 0, iface
->ifindex
, IN6ADDR_ANY_INIT
, 0};
379 socklen_t alen
= sizeof(addr
);
382 if (cfg_proto
&& (cfg_proto
!= 6))
385 addr
.sin6_addr
.s6_addr
[0] = 0xff;
386 addr
.sin6_addr
.s6_addr
[1] = 0x02;
387 addr
.sin6_addr
.s6_addr
[15] = 0x01;
389 sock
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
390 connect(sock
, (struct sockaddr
*)&addr
, sizeof(addr
));
391 ret
= getsockname(sock
, (struct sockaddr
*)&addr
, &alen
);
393 memcpy(&iface
->v6_addr
, &addr
.sin6_addr
, sizeof(iface
->v6_addr
));
394 iface
->mcast_addr
= MCAST_ADDR6
;
401 static int _interface_add(const char *name
, int v6
)
403 struct interface
*iface
;
407 iface
= calloc_a(sizeof(*iface
),
408 &name_buf
, strlen(name
) + 1,
409 &id_buf
, strlen(name
) + 3);
411 sprintf(id_buf
, "%d_%s", v6
, name
);
412 iface
->name
= strcpy(name_buf
, name
);
414 iface
->ifindex
= if_nametoindex(name
);
417 if (iface
->ifindex
<= 0)
420 if (!v6
&& get_iface_ipv4(iface
))
423 if (v6
&& get_iface_ipv6(iface
))
426 vlist_add(&interfaces
, &iface
->node
, iface
->id
);
434 int interface_add(const char *name
)
436 int v4
= _interface_add(name
, 0);
437 int v6
= _interface_add(name
, 1);
442 VLIST_TREE(interfaces
, avl_strcmp
, iface_update_cb
, false, false);