tagging vde-2 version 2.3.2
[vde.git] / 2.3.2 / src / vdetaplib / libvdetap.c
blob00cd401177a5e020e31dce164e9ba2510f6c0814
1 /* Copyright 2004 Renzo Davoli
2 * Reseased under the GPLv2 */
4 #define _GNU_SOURCE
5 #include <dlfcn.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/socket.h>
9 #include <sys/syscall.h>
10 #include <sys/stat.h>
11 #include <stdarg.h>
12 #include <string.h>
13 #include <unistd.h>
14 #include <stdlib.h>
15 #include <fcntl.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <signal.h>
19 #include <linux/ioctl.h>
20 #include <linux/if.h>
21 #include <linux/if_tun.h>
23 #include <config.h>
24 #include <vde.h>
25 #include <vdecommon.h>
27 #define TUNTAPPATH "/dev/net/tun"
28 #define VDETAPEXEC LIBEXECDIR "/vdetap"
29 #define VDEALLTAP "VDEALLTAP"
30 #define MAX 10
32 #define nativesym(function, name) \
33 { \
34 const char *msg; \
35 if (native_##function == NULL) { \
36 *(void **)(&native_##function) = dlsym(RTLD_NEXT, name); \
37 if ((msg = dlerror()) != NULL) { \
38 fprintf (stderr, "%s: dlsym(%s): %s\n", PACKAGE, name, msg); \
39 } \
40 } \
43 static int (*native_ioctl) (int d, int request, ...) = NULL;
44 static int (*native_open) (const char *pathname, int flags, ...) = NULL;
45 static int (*native_open64) (const char *pathname, int flags, ...) = NULL;
47 int tapfd[2] = {-1,-1};
48 static int tapcount=0;
49 static int tuncount=0;
51 static struct pidlist {
52 pid_t pid;
53 struct pidlist *next;
54 } *plh = NULL, *flh=NULL, pidpool[MAX];
56 static struct pidlist *plmalloc(void) {
57 struct pidlist *rv;
58 rv=flh;
59 if (rv != NULL)
60 flh=flh->next;
61 return rv;
64 /* not used?
65 static void plfree (struct pidlist *el) {
66 el->next=flh;
67 flh=el;
71 static int addpid(int pid) {
72 struct pidlist *plp;
73 if ((plp=plmalloc ()) != NULL) {
74 plp->next=plh;
75 plh=plp;
76 plp->pid=pid;
77 return pid;
78 } else {
79 kill(pid,SIGTERM);
80 return -1;
84 void libvdetap_init (void) __attribute((constructor));
85 void libvdetap_init(void)
87 register int i;
88 nativesym(ioctl, "ioctl");
89 nativesym(open, "open");
90 nativesym(open64, "open64");
91 for (i=1;i<MAX;i++)
92 pidpool[i-1].next= &(pidpool[i]);
93 flh=pidpool;
96 void libvdetap_fini(void)
98 struct pidlist *plp=plh;
99 while (plp != NULL) {
100 kill(plp->pid,SIGTERM);
101 plp = plp->next;
105 int open(const char *path, int flags, ...)
107 va_list ap;
108 int data;
110 va_start(ap, flags);
111 data = va_arg(ap, int);
112 va_end(ap);
114 if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
115 if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0)
116 return tapfd[0];
117 else
118 return -1;
120 } else
121 return native_open(path, flags, data);
124 int open64(const char *path, int flags, ...)
126 va_list ap;
127 int data;
129 va_start(ap, flags);
130 data = va_arg(ap, int);
131 va_end(ap);
133 if (strcmp(path,TUNTAPPATH)==0 && tapfd[0] == -1) {
134 if (socketpair(PF_UNIX, SOCK_DGRAM, 0,tapfd) == 0)
135 return tapfd[0];
136 else
137 return -1;
139 } else
140 return native_open64(path, flags | O_LARGEFILE, data);
143 static char *getvdeopt(struct ifreq *ifr,char *suffix)
145 static char buf[16];
146 char *rv;
147 snprintf(buf,16,"%s_%s",ifr->ifr_name,suffix);
148 if ((rv=getenv(buf)) != NULL)
149 return rv;
150 snprintf(buf,16,"VDEALLTAP_%s",suffix);
151 if ((rv=getenv(buf)) != NULL)
152 return rv;
153 else
154 return "";
157 int ioctl(int fd, unsigned long int command, ...)
159 va_list ap;
160 char *data;
161 char *vdesock;
162 int pid;
163 int callerpid=getpid();
165 va_start(ap, command);
166 data = va_arg(ap, char *);
167 va_end(ap);
169 if (fd == tapfd[0]) {
170 if (command == TUNSETIFF) {
171 struct ifreq *ifr = (struct ifreq *) data;
172 char num[5];
173 char name[10];
174 char scallerpid[6];
176 ifr->ifr_name[IFNAMSIZ-1] = '\0';
177 if (ifr->ifr_name[0] == 0) {
178 if (ifr->ifr_flags & IFF_TAP)
179 sprintf(name,"tap%d",tapcount++);
180 else
181 sprintf(name,"tun%d",tuncount++);
182 strncpy(ifr->ifr_name,name,IFNAMSIZ);
184 else if (strchr(ifr->ifr_name, '%') != NULL) {
185 sprintf(name,ifr->ifr_name,tapcount++);
186 strncpy(ifr->ifr_name,name,IFNAMSIZ);
188 if ((ifr->ifr_flags & IFF_TAP) && (
189 /* from env: single interface or VDEALLTAP */
190 ((vdesock=getenv(ifr->ifr_name)) != NULL) ||
191 (vdesock=getenv(VDEALLTAP)) != NULL)
193 if ((pid=fork()) < 0) {
194 close(tapfd[1]);
195 errno=EINVAL;
196 return -1;
197 } else if (pid > 0) { /*father*/
198 if((pid=addpid(pid)) < 0) {
199 close(tapfd[0]);
200 close(tapfd[1]);
201 return -1;
202 } else {
203 close(tapfd[1]);
204 return 0;
206 } else { /*son*/
207 plh=NULL;
208 close(tapfd[0]);
209 sprintf(num,"%d",tapfd[1]);
210 sprintf(scallerpid,"%d",callerpid);
211 return execlp(VDETAPEXEC,"-",num,vdesock,ifr->ifr_name,
212 scallerpid,
213 getvdeopt(ifr,"port"),
214 getvdeopt(ifr,"group"),
215 getvdeopt(ifr,"mode"),
216 (char *) 0);
219 else /*roll back to the native tuntap*/
221 int newfd;
222 int saverrno;
223 int resultioctl;
224 close(tapfd[1]);
225 if ((newfd=native_open(TUNTAPPATH, O_RDWR, 0)) < 0) {
226 saverrno=errno;
227 close(tapfd[0]);
228 errno=saverrno;
229 return -1;
230 } else
232 resultioctl=native_ioctl(fd, command, data);
233 if (resultioctl < 0) {
234 saverrno=errno;
235 close(tapfd[0]);
236 errno=saverrno;
237 return -1;
238 } else {
239 dup2(newfd,tapfd[0]);
240 return resultioctl;
244 } else
245 return 0;
246 } else
247 return (native_ioctl(fd, command, data));