2 device.c -- UML network 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.
34 static int listen_fd
= -1;
35 static int request_fd
= -1;
36 static int data_fd
= -1;
37 static int write_fd
= -1;
39 static char *device_info
;
41 enum request_type
{ REQ_NEW_CONTROL
};
43 static struct request
{
46 enum request_type type
;
47 struct sockaddr_un sock
;
50 static struct sockaddr_un data_sun
;
52 static bool setup_device(void) {
53 struct sockaddr_un listen_sun
;
54 static const int one
= 1;
62 if(!get_config_string(lookup_config(config_tree
, "Device"), &device
))
63 xasprintf(&device
, LOCALSTATEDIR
"/run/%s.umlsocket", identname
);
65 get_config_string(lookup_config(config_tree
, "Interface"), &iface
);
67 device_info
= "UML network socket";
69 if((write_fd
= socket(PF_UNIX
, SOCK_DGRAM
, 0)) < 0) {
70 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not open write %s: %s", device_info
, strerror(errno
));
76 fcntl(write_fd
, F_SETFD
, FD_CLOEXEC
);
79 setsockopt(write_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof one
);
81 if(fcntl(write_fd
, F_SETFL
, O_NONBLOCK
) < 0) {
82 logger(DEBUG_ALWAYS
, LOG_ERR
, "System call `%s' failed: %s", "fcntl", strerror(errno
));
87 if((data_fd
= socket(PF_UNIX
, SOCK_DGRAM
, 0)) < 0) {
88 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not open data %s: %s", device_info
, strerror(errno
));
94 fcntl(data_fd
, F_SETFD
, FD_CLOEXEC
);
97 setsockopt(data_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof one
);
99 if(fcntl(data_fd
, F_SETFL
, O_NONBLOCK
) < 0) {
100 logger(DEBUG_ALWAYS
, LOG_ERR
, "System call `%s' failed: %s", "fcntl", strerror(errno
));
107 gettimeofday(&tv
, NULL
);
108 name
.usecs
= tv
.tv_usec
;
109 data_sun
.sun_family
= AF_UNIX
;
110 memcpy(&data_sun
.sun_path
, &name
, sizeof name
);
112 if(bind(data_fd
, (struct sockaddr
*)&data_sun
, sizeof data_sun
) < 0) {
113 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not bind data %s: %s", device_info
, strerror(errno
));
118 if((listen_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0) {
119 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not open %s: %s", device_info
,
125 fcntl(device_fd
, F_SETFD
, FD_CLOEXEC
);
128 setsockopt(listen_fd
, SOL_SOCKET
, SO_REUSEADDR
, &one
, sizeof one
);
130 if(fcntl(listen_fd
, F_SETFL
, O_NONBLOCK
) < 0) {
131 logger(DEBUG_ALWAYS
, LOG_ERR
, "System call `%s' failed: %s", "fcntl", strerror(errno
));
135 listen_sun
.sun_family
= AF_UNIX
;
136 strncpy(listen_sun
.sun_path
, device
, sizeof listen_sun
.sun_path
);
137 if(bind(listen_fd
, (struct sockaddr
*)&listen_sun
, sizeof listen_sun
) < 0) {
138 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not bind %s to %s: %s", device_info
, device
, strerror(errno
));
142 if(listen(listen_fd
, 1) < 0) {
143 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not listen on %s %s: %s", device_info
, device
, strerror(errno
));
147 device_fd
= listen_fd
;
150 logger(DEBUG_ALWAYS
, LOG_INFO
, "%s is a %s", device
, device_info
);
152 if(routing_mode
== RMODE_ROUTER
)
153 overwrite_mac
= true;
158 void close_device(void) {
160 close(listen_fd
); listen_fd
= -1;
163 if(request_fd
>= 0) {
164 close(request_fd
); request_fd
= -1;
168 close(data_fd
); data_fd
= -1;
172 close(write_fd
); write_fd
= -1;
177 free(device
); device
= NULL
;
179 free(iface
); iface
= NULL
;
184 static bool read_packet(vpn_packet_t
*packet
) {
190 socklen_t salen
= sizeof sa
;
192 request_fd
= accept(listen_fd
, &sa
, &salen
);
194 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not accept connection to %s %s: %s", device_info
, device
, strerror(errno
));
199 fcntl(request_fd
, F_SETFD
, FD_CLOEXEC
);
202 if(fcntl(listen_fd
, F_SETFL
, O_NONBLOCK
) < 0) {
203 logger(DEBUG_ALWAYS
, LOG_ERR
, "System call `%s' failed: %s", "fcntl", strerror(errno
));
210 device_fd
= request_fd
;
217 if((inlen
= read(request_fd
, &request
, sizeof request
)) != sizeof request
) {
218 logger(DEBUG_ALWAYS
, LOG_ERR
, "Error while reading request from %s %s: %s", device_info
,
219 device
, strerror(errno
));
224 if(request
.magic
!= 0xfeedface || request
.version
!= 3 || request
.type
!= REQ_NEW_CONTROL
) {
225 logger(DEBUG_ALWAYS
, LOG_ERR
, "Unknown magic %x, version %d, request type %d from %s %s",
226 request
.magic
, request
.version
, request
.type
, device_info
, device
);
231 if(connect(write_fd
, &request
.sock
, sizeof request
.sock
) < 0) {
232 logger(DEBUG_ALWAYS
, LOG_ERR
, "Could not bind write %s: %s", device_info
, strerror(errno
));
237 write(request_fd
, &data_sun
, sizeof data_sun
);
240 logger(DEBUG_ALWAYS
, LOG_INFO
, "Connection with UML established");
247 if((inlen
= read(data_fd
, DATA(packet
), MTU
)) <= 0) {
248 logger(DEBUG_ALWAYS
, LOG_ERR
, "Error while reading from %s %s: %s", device_info
,
249 device
, strerror(errno
));
256 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Read packet of %d bytes from %s", packet
->len
,
263 logger(DEBUG_ALWAYS
, LOG_ERR
, "Invalid value for state variable in " __FILE__
);
268 static bool write_packet(vpn_packet_t
*packet
) {
270 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Dropping packet of %d bytes to %s: not connected to UML yet",
271 packet
->len
, device_info
);
275 logger(DEBUG_TRAFFIC
, LOG_DEBUG
, "Writing packet of %d bytes to %s",
276 packet
->len
, device_info
);
278 if(write(write_fd
, DATA(packet
), packet
->len
) < 0) {
279 if(errno
!= EINTR
&& errno
!= EAGAIN
) {
280 logger(DEBUG_ALWAYS
, LOG_ERR
, "Can't write to %s %s: %s", device_info
, device
, strerror(errno
));
290 const devops_t uml_devops
= {
291 .setup
= setup_device
,
292 .close
= close_device
,
294 .write
= write_packet
,