all the python scripts are for python2, and fedora31 requires to be specific
[vsys-scripts.git] / root-context / fd_tuntap.c
1 /* fd_tuntap.c: VSYS script to allocate slice-local tuntap interfaces.
2  *   Thom Haddow - 06/09/09
3  *
4  * Reads interface type from local control unix socket, replies with fd for new
5  * (unconfigured) tuntap interface. VSYS client can get interface name with
6  * TUNGETIFF ioctl. 
7  */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <unistd.h>
13 #include <fcntl.h>
14 #include <errno.h>
15 #include <pwd.h>
16 #include <sys/ioctl.h>
17 #include <sys/socket.h>
18 #include <sys/types.h>
19 #include <linux/if.h>
20 #include <linux/if_tun.h>
21
22 int send_vif_fd(int sock_fd, int vif_fd, char *vif_name)
23 {
24         int retval;
25         struct msghdr msg;
26         struct cmsghdr *p_cmsg;
27         struct iovec vec;
28         size_t cmsgbuf[CMSG_SPACE(sizeof(vif_fd)) / sizeof(size_t)];
29         int *p_fds;
30
31
32         msg.msg_control = cmsgbuf;
33         msg.msg_controllen = sizeof(cmsgbuf);
34         p_cmsg = CMSG_FIRSTHDR(&msg);
35         p_cmsg->cmsg_level = SOL_SOCKET;
36         p_cmsg->cmsg_type = SCM_RIGHTS;
37         p_cmsg->cmsg_len = CMSG_LEN(sizeof(vif_fd));
38         p_fds = (int *) CMSG_DATA(p_cmsg);
39         *p_fds = vif_fd;
40         msg.msg_controllen = p_cmsg->cmsg_len;
41         msg.msg_name = NULL;
42         msg.msg_namelen = 0;
43         msg.msg_iov = &vec;
44         msg.msg_iovlen = 1;
45         msg.msg_flags = 0;
46
47     /* Send the interface name as the iov */
48         vec.iov_base = vif_name;
49         vec.iov_len = strlen(vif_name)+1;
50
51         while ((retval = sendmsg(sock_fd, &msg, 0)) == -1 && errno == EINTR);
52         if (retval != 1) {
53                 perror("sending file descriptor");
54                 return -1;
55         }
56         return 0;
57 }
58
59
60
61 int main(int argc, char *argv[])
62 {
63     int control_channel_fd;
64     int tap_fd;
65     int slice_uid;
66     char if_name[IFNAMSIZ];
67     int if_type;
68     struct ifreq ifr;
69     struct passwd *pwd;
70    
71     if(argc < 3) {
72         printf("This script is called by vsys.\n");
73         exit(-1);
74     }
75
76
77     /* Get slice UID and control channel fd from VSYS args */ 
78     pwd = getpwnam(argv[1]);
79     if(pwd==NULL) {
80         perror("Failed to lookup UID");
81         exit(-1);
82     }
83     slice_uid = pwd->pw_uid;
84     sscanf(argv[2],"%d", &control_channel_fd);
85
86    
87      
88     /* Get type param from control channel. */
89     if(recv(control_channel_fd, &if_type, sizeof(int), 0) != sizeof(int)) {
90         perror("fd_tuntap: Failed to read from control channel");
91         exit(-1);
92     }
93     
94    
95     /* Generate basename for interface */
96     if(if_type==IFF_TUN) {
97         sprintf(if_name, "tun%d-%%d", slice_uid);
98     }
99     else if(if_type==IFF_TAP) {
100         sprintf(if_name, "tap%d-%%d", slice_uid);
101     }
102     else { /* TODO: Might also want to allow the other types? */
103         fprintf(stderr, "fd_tuntap: %d is not a valid interface type",if_type);
104         exit(-1); 
105     }
106
107     /* Open tun device */
108     if( (tap_fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
109         system("modprobe tun");
110         system("ln -sf /dev/net/tun /dev/stdtun");
111         if( (tap_fd = open("/dev/net/tun", O_RDWR)) < 0 ) {
112             perror("ERROR: tun_alloc():open(/dev/net/tun)");
113             exit(-1);
114         }
115     }
116
117
118     /* Set interface type */
119     memset(&ifr, 0, sizeof(ifr));
120     ifr.ifr_flags = if_type; 
121     strncpy(ifr.ifr_name, if_name, IFNAMSIZ);
122     
123     if( ioctl(tap_fd, TUNSETIFF, (void *) &ifr) < 0 ) {
124         close(tap_fd);
125         perror("fd_tuntap: Failed to set tun/tap name");
126     }
127
128     /* Read initialised interface name */
129     strcpy(if_name, ifr.ifr_name);
130
131
132     /* Send tap_fd to slice */
133     send_vif_fd(control_channel_fd, tap_fd, if_name);
134
135     return 0;
136 }