2 device.c -- multicast socket
3 Copyright (C) 2002-2005 Ivo Timmermans,
4 2002-2013 Guus Sliepen <guus@tinc-vpn.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License along
17 with this program; if not, write to the Free Software Foundation, Inc.,
18 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
32 static char *device_info
;
34 static struct addrinfo
*ai
= NULL
;
35 static mac_t ignore_src
= {{0}};
37 static bool setup_device(void) {
43 device_info
= "multicast socket";
45 get_config_string(lookup_config(config_tree
, "Interface"), &iface
);
47 if(!get_config_string(lookup_config(config_tree
, "Device"), &device
)) {
48 logger(DEBUG_ALWAYS
, LOG_ERR
, "Device variable required for %s", device_info
);
52 host
= xstrdup(device
);
53 space
= strchr(host
, ' ');
55 logger(DEBUG_ALWAYS
, LOG_ERR
, "Port number required for %s", device_info
);
61 space
= strchr(port
, ' ');
68 ai
= str2addrinfo(host
, port
, SOCK_DGRAM
);
72 device_fd
= socket(ai
->ai_family
, SOCK_DGRAM
, IPPROTO_UDP
);
74 logger(DEBUG_ALWAYS
, LOG_ERR
, "Creating socket failed: %s", sockstrerror(sockerrno
));
79 fcntl(device_fd
, F_SETFD
, FD_CLOEXEC
);
82 static const int one
= 1;
83 setsockopt(device_fd
, SOL_SOCKET
, SO_REUSEADDR
, (void *)&one
, sizeof one
);
85 if(bind(device_fd
, ai
->ai_addr
, ai
->ai_addrlen
)) {
86 logger(DEBUG_ALWAYS
, LOG_ERR
, "Can't bind to %s %s: %s", host
, port
, sockstrerror(sockerrno
));
90 switch(ai
->ai_family
) {
91 #ifdef IP_ADD_MEMBERSHIP
94 struct sockaddr_in in
;
95 memcpy(&in
, ai
->ai_addr
, sizeof in
);
96 mreq
.imr_multiaddr
.s_addr
= in
.sin_addr
.s_addr
;
97 mreq
.imr_interface
.s_addr
= htonl(INADDR_ANY
);
98 if(setsockopt(device_fd
, IPPROTO_IP
, IP_ADD_MEMBERSHIP
, (void *)&mreq
, sizeof mreq
)) {
99 logger(DEBUG_ALWAYS
, LOG_ERR
, "Cannot join multicast group %s %s: %s", host
, port
, sockstrerror(sockerrno
));
102 #ifdef IP_MULTICAST_LOOP
103 setsockopt(device_fd
, IPPROTO_IP
, IP_MULTICAST_LOOP
, (const void *)&one
, sizeof one
);
105 #ifdef IP_MULTICAST_TTL
106 setsockopt(device_fd
, IPPROTO_IP
, IP_MULTICAST_TTL
, (void *)&ttl
, sizeof ttl
);
111 #ifdef IPV6_JOIN_GROUP
113 struct ipv6_mreq mreq
;
114 struct sockaddr_in6 in6
;
115 memcpy(&in6
, ai
->ai_addr
, sizeof in6
);
116 memcpy(&mreq
.ipv6mr_multiaddr
, &in6
.sin6_addr
, sizeof mreq
.ipv6mr_multiaddr
);
117 mreq
.ipv6mr_interface
= in6
.sin6_scope_id
;
118 if(setsockopt(device_fd
, IPPROTO_IPV6
, IPV6_JOIN_GROUP
, (void *)&mreq
, sizeof mreq
)) {
119 logger(DEBUG_ALWAYS
, LOG_ERR
, "Cannot join multicast group %s %s: %s", host
, port
, sockstrerror(sockerrno
));
122 #ifdef IPV6_MULTICAST_LOOP
123 setsockopt(device_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_LOOP
, (const void *)&one
, sizeof one
);
125 #ifdef IPV6_MULTICAST_HOPS
126 setsockopt(device_fd
, IPPROTO_IPV6
, IPV6_MULTICAST_HOPS
, (void *)&ttl
, sizeof ttl
);
132 logger(DEBUG_ALWAYS
, LOG_ERR
, "Multicast for address family %hx unsupported", ai
->ai_family
);
136 logger(DEBUG_ALWAYS
, LOG_INFO
, "%s is a %s", device
, device_info
);
142 closesocket(device_fd
);
150 static void close_device(void) {
160 static bool read_packet(vpn_packet_t
*packet
) {
163 if((lenin
= recv(device_fd
, (void *)packet
->data
, MTU
, 0)) <= 0) {
164 logger(DEBUG_ALWAYS
, LOG_ERR
, "Error while reading from %s %s: %s", device_info
,
165 device
, strerror(errno
));
169 if(!memcmp(&ignore_src
, packet
->data
+ 6, sizeof ignore_src
)) {
170 logger(DEBUG_SCARY_THINGS
, LOG_DEBUG
, "Ignoring loopback packet of %d bytes from %s", lenin
, device_info
);
176 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Read packet of %d bytes from %s", packet
->len
,
182 static bool write_packet(vpn_packet_t
*packet
) {
183 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Writing packet of %d bytes to %s",
184 packet
->len
, device_info
);
186 if(sendto(device_fd
, (void *)packet
->data
, packet
->len
, 0, ai
->ai_addr
, ai
->ai_addrlen
) < 0) {
187 logger(DEBUG_ALWAYS
, LOG_ERR
, "Can't write to %s %s: %s", device_info
, device
,
192 memcpy(&ignore_src
, packet
->data
+ 6, sizeof ignore_src
);
197 const devops_t multicast_devops
= {
198 .setup
= setup_device
,
199 .close
= close_device
,
201 .write
= write_packet
,