1 /* source: xio-tun.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses of tun/tap type */
7 #include "xiosysincludes.h"
11 #include "xio-named.h"
12 #include "xio-socket.h"
18 static int xioopen_tun(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*fd
, unsigned groups
, int dummy1
, int dummy2
, int dummy3
);
20 /****** TUN addresses ******/
21 const struct optdesc opt_tun_device
= { "tun-device", NULL
, OPT_TUN_DEVICE
, GROUP_TUN
, PH_OPEN
, TYPE_FILENAME
, OFUNC_SPEC
};
22 const struct optdesc opt_tun_name
= { "tun-name", NULL
, OPT_TUN_NAME
, GROUP_INTERFACE
, PH_FD
, TYPE_STRING
, OFUNC_SPEC
};
23 const struct optdesc opt_tun_type
= { "tun-type", NULL
, OPT_TUN_TYPE
, GROUP_INTERFACE
, PH_FD
, TYPE_STRING
, OFUNC_SPEC
};
24 const struct optdesc opt_iff_no_pi
= { "iff-no-pi", "no-pi", OPT_IFF_NO_PI
, GROUP_TUN
, PH_FD
, TYPE_BOOL
, OFUNC_SPEC
};
25 /*0 const struct optdesc opt_interface_addr = { "interface-addr", "address", OPT_INTERFACE_ADDR, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
26 /*0 const struct optdesc opt_interface_netmask = { "interface-netmask", "netmask", OPT_INTERFACE_NETMASK, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };*/
27 const struct optdesc opt_iff_up
= { "iff-up", "up", OPT_IFF_UP
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_UP
};
28 const struct optdesc opt_iff_broadcast
= { "iff-broadcast", NULL
, OPT_IFF_BROADCAST
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_BROADCAST
};
29 const struct optdesc opt_iff_debug
= { "iff-debug" , NULL
, OPT_IFF_DEBUG
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_DEBUG
};
30 const struct optdesc opt_iff_loopback
= { "iff-loopback" , "loopback", OPT_IFF_LOOPBACK
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_LOOPBACK
};
31 const struct optdesc opt_iff_pointopoint
= { "iff-pointopoint", "pointopoint",OPT_IFF_POINTOPOINT
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_POINTOPOINT
};
32 const struct optdesc opt_iff_notrailers
= { "iff-notrailers", "notrailers", OPT_IFF_NOTRAILERS
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_NOTRAILERS
};
33 const struct optdesc opt_iff_running
= { "iff-running", "running", OPT_IFF_RUNNING
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_RUNNING
};
34 const struct optdesc opt_iff_noarp
= { "iff-noarp", "noarp", OPT_IFF_NOARP
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_NOARP
};
35 const struct optdesc opt_iff_promisc
= { "iff-promisc", "promisc", OPT_IFF_PROMISC
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_PROMISC
};
36 const struct optdesc opt_iff_allmulti
= { "iff-allmulti", "allmulti", OPT_IFF_ALLMULTI
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_ALLMULTI
};
37 const struct optdesc opt_iff_master
= { "iff-master", "master", OPT_IFF_MASTER
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_MASTER
};
38 const struct optdesc opt_iff_slave
= { "iff-slave", "slave", OPT_IFF_SLAVE
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_SLAVE
};
39 const struct optdesc opt_iff_multicast
= { "iff-multicast", NULL
, OPT_IFF_MULTICAST
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_MULTICAST
};
40 const struct optdesc opt_iff_portsel
= { "iff-portsel", "portsel", OPT_IFF_PORTSEL
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_PORTSEL
};
41 const struct optdesc opt_iff_automedia
= { "iff-automedia", "automedia", OPT_IFF_AUTOMEDIA
, GROUP_INTERFACE
, PH_FD
, TYPE_BOOL
, OFUNC_OFFSET_MASKS
, XIO_OFFSETOF(para
.tun
.iff_opts
), XIO_SIZEOF(para
.tun
.iff_opts
), IFF_AUTOMEDIA
};
42 /*const struct optdesc opt_iff_dynamic = { "iff-dynamic", "dynamic", OPT_IFF_DYNAMIC, GROUP_INTERFACE, PH_FD, TYPE_BOOL, OFUNC_OFFSET_MASKS, XIO_OFFSETOF(para.tun.iff_opts), XIO_SIZEOF(short), IFF_DYNAMIC };*/
44 const struct optdesc opt_route
= { "route", NULL
, OPT_ROUTE
, GROUP_INTERFACE
, PH_INIT
, TYPE_STRING
, OFUNC_SPEC
};
47 const struct addrdesc xioaddr_tun
= { "tun", 3, xioopen_tun
, GROUP_FD
|GROUP_CHR
|GROUP_NAMED
|GROUP_OPEN
|GROUP_TUN
, 0, 0, 0 HELP("[:<ip-addr>/<bits>]") };
49 // "route"=address/netmask
50 // "ip6-route"=address/netmask
59 /* sub options for route option */
61 static const struct optdesc opt_route_tos
= { "route", NULL
, IFOPT_ROUTE
, };
62 static const struct optname xio_route_options
[] = {
63 {"tos", &xio_route_tos
}
67 static int xioopen_tun(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xfd
, unsigned groups
, int dummy1
, int dummy2
, int dummy3
) {
68 char *tundevice
= NULL
;
69 char *tunname
= NULL
, *tuntype
= NULL
;
70 int pf
= /*! PF_UNSPEC*/ PF_INET
;
71 struct xiorange network
;
73 const char *namedargv
[] = { "tun", NULL
, NULL
};
74 int rw
= (xioflags
& XIO_ACCMODE
);
81 if (argc
> 2 || argc
< 0) {
82 Error2("%s: wrong number of parameters (%d instead of 0 or 1)",
86 if (retropt_string(opts
, OPT_TUN_DEVICE
, &tundevice
) != 0) {
87 tundevice
= strdup("/dev/net/tun");
90 /*! socket option here? */
91 retropt_socket_pf(opts
, &pf
);
93 namedargv
[1] = tundevice
;
94 /* open the tun cloning device */
95 if ((result
= _xioopen_named_early(2, namedargv
, xfd
, groups
, &exists
, opts
)) < 0) {
99 /*========================= the tunnel interface =========================*/
100 Notice("creating tunnel network interface");
101 if ((result
= _xioopen_open(tundevice
, rw
, opts
)) < 0)
103 xfd
->stream
.fd
= result
;
105 /* prepare configuration of the new network interface */
106 memset(&ifr
, 0,sizeof(ifr
));
108 if (retropt_string(opts
, OPT_TUN_NAME
, &tunname
) == 0) {
109 strncpy(ifr
.ifr_name
, tunname
, IFNAMSIZ
); /* ok */
112 ifr
.ifr_name
[0] = '\0';
115 ifr
.ifr_flags
= IFF_TUN
;
116 if (retropt_string(opts
, OPT_TUN_TYPE
, &tuntype
) == 0) {
117 if (!strcmp(tuntype
, "tap")) {
118 ifr
.ifr_flags
= IFF_TAP
;
119 } else if (strcmp(tuntype
, "tun")) {
120 Error1("unknown tun-type \"%s\"", tuntype
);
124 if (retropt_bool(opts
, OPT_IFF_NO_PI
, &no_pi
) == 0) {
126 ifr
.ifr_flags
|= IFF_NO_PI
;
127 #if 0 /* not neccessary for now */
129 ifr
.ifr_flags
&= ~IFF_NO_PI
;
134 if (Ioctl(xfd
->stream
.fd
, TUNSETIFF
, &ifr
) < 0) {
135 Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
136 xfd
->stream
.fd
, ifr
.ifr_name
, strerror(errno
));
137 Close(xfd
->stream
.fd
);
140 /*===================== setting interface properties =====================*/
142 /* we seem to need a socket for manipulating the interface */
143 if ((sockfd
= Socket(PF_INET
, SOCK_DGRAM
, 0)) < 0) {
144 Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno
));
145 sockfd
= xfd
->stream
.fd
; /* desparate fallback attempt */
148 /*--------------------- setting interface address and netmask ------------*/
150 if ((ifaddr
= strdup(argv
[1])) == NULL
) {
151 Error1("strdup(\"%s\"): out of memory", argv
[1]);
152 return STAT_RETRYLATER
;
154 if ((result
= xioparsenetwork(ifaddr
, pf
, &network
)) != STAT_OK
) {
158 socket_init(pf
, (union sockaddr_union
*)&ifr
.ifr_addr
);
159 ((struct sockaddr_in
*)&ifr
.ifr_addr
)->sin_addr
=
160 network
.netaddr
.ip4
.sin_addr
;
161 if (Ioctl(sockfd
, SIOCSIFADDR
, &ifr
) < 0) {
162 Error4("ioctl(%d, SIOCSIFADDR, {\"%s\", \"%s\"}: %s",
163 sockfd
, ifr
.ifr_name
, ifaddr
, strerror(errno
));
165 ((struct sockaddr_in
*)&ifr
.ifr_netmask
)->sin_addr
=
166 network
.netmask
.ip4
.sin_addr
;
167 if (Ioctl(sockfd
, SIOCSIFNETMASK
, &ifr
) < 0) {
168 Error4("ioctl(%d, SIOCSIFNETMASK, {\"0x%08u\", \"%s\"}, %s",
169 sockfd
, ((struct sockaddr_in
*)&ifr
.ifr_netmask
)->sin_addr
.s_addr
,
170 ifaddr
, strerror(errno
));
174 /*--------------------- setting interface flags --------------------------*/
175 applyopts_single(&xfd
->stream
, opts
, PH_FD
);
177 if (Ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
178 Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
179 sockfd
, ifr
.ifr_name
, strerror(errno
));
181 Debug2("\"%s\": system set flags: 0x%hx", ifr
.ifr_name
, ifr
.ifr_flags
);
182 ifr
.ifr_flags
|= xfd
->stream
.para
.tun
.iff_opts
[0];
183 ifr
.ifr_flags
&= ~xfd
->stream
.para
.tun
.iff_opts
[1];
184 Debug2("\"%s\": xio merged flags: 0x%hx", ifr
.ifr_name
, ifr
.ifr_flags
);
185 if (Ioctl(sockfd
, SIOCSIFFLAGS
, &ifr
) < 0) {
186 Error4("ioctl(%d, SIOCSIFFLAGS, {\"%s\", %hd}: %s",
187 sockfd
, ifr
.ifr_name
, ifr
.ifr_flags
, strerror(errno
));
190 if (Ioctl(sockfd
, SIOCGIFFLAGS
, &ifr
) < 0) {
191 Error3("ioctl(%d, SIOCGIFFLAGS, {\"%s\"}: %s",
192 sockfd
, ifr
.ifr_name
, strerror(errno
));
194 Debug2("\"%s\": resulting flags: 0x%hx", ifr
.ifr_name
, ifr
.ifr_flags
);
198 applyopts_named(tundevice
, opts
, PH_FD
);
200 applyopts(xfd
->stream
.fd
, opts
, PH_FD
);
201 applyopts_cloexec(xfd
->stream
.fd
, opts
);
203 applyopts_fchown(xfd
->stream
.fd
, opts
);
205 if ((result
= _xio_openlate(&xfd
->stream
, opts
)) < 0)
211 #endif /* WITH_TUN */