Version 1.8.0.0
[socat.git] / xio-tun.c
blobf66be7e1aac3803b1deb335c79a6b9328dc6f0b4
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"
8 #if WITH_TUN
9 #include "xioopen.h"
11 #include "xio-named.h"
12 #include "xio-socket.h"
13 #include "xio-ip.h"
14 #include "xio-interface.h"
16 #include "xio-tun.h"
19 static int xioopen_tun(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
21 /****** TUN options ******/
22 const struct optdesc opt_tun_device = { "tun-device", NULL, OPT_TUN_DEVICE, GROUP_TUN, PH_OPEN, TYPE_FILENAME, OFUNC_SPEC };
23 const struct optdesc opt_tun_name = { "tun-name", NULL, OPT_TUN_NAME, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };
24 const struct optdesc opt_tun_type = { "tun-type", NULL, OPT_TUN_TYPE, GROUP_INTERFACE, PH_FD, TYPE_STRING, OFUNC_SPEC };
25 const struct optdesc opt_iff_no_pi = { "iff-no-pi", "no-pi", OPT_IFF_NO_PI, GROUP_TUN, PH_FD, TYPE_BOOL, OFUNC_SPEC };
27 /****** TUN addresses ******/
28 const struct addrdesc xioaddr_tun = { "TUN", 3, xioopen_tun, GROUP_FD|GROUP_CHR|GROUP_OPEN|GROUP_TUN, 0, 0, 0 HELP("[:<ip-addr>/<bits>]") };
29 /* "if-name"=tun3
30 // "route"=address/netmask
31 // "ip6-route"=address/netmask
32 // "iff-broadcast"
33 // "iff-debug"
34 // "iff-promisc"
35 // see .../linux/if.h
39 #if LATER
40 /* sub options for route option */
41 #define IFOPT_ROUTE 1
42 static const struct optdesc opt_route_tos = { "route", NULL, IFOPT_ROUTE, };
43 static const struct optname xio_route_options[] = {
44 {"tos", &xio_route_tos }
45 } ;
46 #endif
48 static int xioopen_tun(
49 int argc,
50 const char *argv[],
51 struct opt *opts,
52 int xioflags,
53 xiofile_t *xfd,
54 const struct addrdesc *addrdesc)
56 struct single *sfd = &xfd->stream;
57 char *tundevice = NULL;
58 char *tunname = NULL, *tuntype = NULL;
59 int pf = /*! PF_UNSPEC*/ PF_INET;
60 struct xiorange network;
61 bool no_pi = false;
62 const char *namedargv[] = { "tun", NULL, NULL };
63 int rw = (xioflags & XIO_ACCMODE);
64 bool exists;
65 struct ifreq ifr;
66 int sockfd;
67 char *ifaddr;
68 int result;
70 if (argc > 2 || argc < 0) {
71 #if WITH_HELP
72 Error3("%s: wrong number of parameters (%d instead of 0 or 1); usage: %s",
73 argv[0], argc-1, addrdesc->syntax);
74 #else
75 Error2("%s: wrong number of parameters (%d instead of 0 or 1)",
76 argv[0], argc-1);
77 #endif
80 if (retropt_string(opts, OPT_TUN_DEVICE, &tundevice) != 0) {
81 tundevice = strdup("/dev/net/tun");
84 /*! socket option here? */
85 retropt_socket_pf(opts, &pf);
87 namedargv[1] = tundevice;
88 /* open the tun cloning device */
89 if ((result = _xioopen_named_early(2, namedargv, xfd, addrdesc->groups,
90 &exists, opts, addrdesc->syntax)) < 0) {
91 return result;
94 /*========================= the tunnel interface =========================*/
95 Notice("creating tunnel network interface");
96 applyopts_optgroup(&xfd->stream, -1, opts, GROUP_PROCESS);
97 if ((result = _xioopen_open(tundevice, rw, opts)) < 0)
98 return result;
99 sfd->fd = result;
101 /* prepare configuration of the new network interface */
102 memset(&ifr, 0, sizeof(ifr));
104 if (retropt_string(opts, OPT_TUN_NAME, &tunname) == 0) {
105 strncpy(ifr.ifr_name, tunname, IFNAMSIZ); /* ok */
106 free(tunname);
107 } else {
108 ifr.ifr_name[0] = '\0';
111 ifr.ifr_flags = IFF_TUN;
112 if (retropt_string(opts, OPT_TUN_TYPE, &tuntype) == 0) {
113 if (!strcmp(tuntype, "tap")) {
114 ifr.ifr_flags = IFF_TAP;
115 } else if (strcmp(tuntype, "tun")) {
116 Error1("unknown tun-type \"%s\"", tuntype);
120 if (retropt_bool(opts, OPT_IFF_NO_PI, &no_pi) == 0) {
121 if (no_pi) {
122 ifr.ifr_flags |= IFF_NO_PI;
123 #if 0 /* not neccessary for now */
124 } else {
125 ifr.ifr_flags &= ~IFF_NO_PI;
126 #endif
130 if (Ioctl(sfd->fd, TUNSETIFF, &ifr) < 0) {
131 Error3("ioctl(%d, TUNSETIFF, {\"%s\"}: %s",
132 sfd->fd, ifr.ifr_name, strerror(errno));
133 Close(sfd->fd);
135 Notice1("TUN: new device \"%s\"", ifr.ifr_name);
137 /*===================== setting interface properties =====================*/
139 /* we seem to need a socket for manipulating the interface */
140 if ((sockfd = Socket(PF_INET, SOCK_DGRAM, 0)) < 0) {
141 Error1("socket(PF_INET, SOCK_DGRAM, 0): %s", strerror(errno));
142 sockfd = sfd->fd; /* desparate fallback attempt */
145 /*--------------------- setting interface address and netmask ------------*/
146 if (argc == 2) {
147 if ((ifaddr = strdup(argv[1])) == NULL) {
148 Error1("strdup(\"%s\"): out of memory", argv[1]);
149 return STAT_RETRYLATER;
151 if ((result = xioparsenetwork(ifaddr, pf, &network,
152 sfd->para.socket.ip.ai_flags))
153 != STAT_OK) {
154 /*! recover */
155 return result;
157 socket_init(pf, (union sockaddr_union *)&ifr.ifr_addr);
158 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr =
159 network.netaddr.ip4.sin_addr;
160 if (Ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) {
161 Error4("ioctl(%d, SIOCSIFADDR, {\"%s\", \"%s\"}: %s",
162 sockfd, ifr.ifr_name, ifaddr, strerror(errno));
164 ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr =
165 network.netmask.ip4.sin_addr;
166 if (Ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) {
167 Error4("ioctl(%d, SIOCSIFNETMASK, {\"0x%08u\", \"%s\"}, %s",
168 sockfd, ((struct sockaddr_in *)&ifr.ifr_netmask)->sin_addr.s_addr,
169 ifaddr, strerror(errno));
171 free(ifaddr);
173 /*--------------------- setting interface flags --------------------------*/
174 applyopts_single(sfd, opts, PH_FD);
176 _xiointerface_apply_iff(sockfd, ifr.ifr_name, sfd->para.interface.iff_opts);
177 if (_interface_retrieve_vlan(&xfd->stream, opts) < 0)
178 return STAT_NORETRY;
180 applyopts(sfd, -1, opts, PH_FD);
181 applyopts_cloexec(sfd->fd, opts);
183 applyopts_fchown(sfd->fd, opts);
185 if ((result = _xio_openlate(sfd, opts)) < 0)
186 return result;
188 return 0;
191 #endif /* WITH_TUN */