added some comments in wirefilter
[vde.git] / vde-2 / slirpvde / slirpvde.c
blobdb72a237fbfc5643b564a0a976424a46889ed7d6
1 /* Copyright 2003 Renzo Davoli
2 * Licensed under the GPL
3 */
5 #include <config.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <signal.h>
9 #include <errno.h>
10 #include <unistd.h>
11 #include <stdint.h>
12 #include <libgen.h>
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
15 #include <sys/un.h>
16 #include <sys/uio.h>
17 #include <sys/poll.h>
18 #include <libslirp.h>
19 #include <pwd.h>
20 #include <grp.h>
21 #include <getopt.h>
23 #define SWITCH_MAGIC 0xfeedface
24 #define BUFSIZE 2048
25 #define ETH_ALEN 6
27 int dhcpmgmt=0;
29 enum request_type { REQ_NEW_CONTROL };
31 #define MAXDESCR 128
33 struct request_v3 {
34 uint32_t magic;
35 uint32_t version;
36 enum request_type type;
37 struct sockaddr_un sock;
38 char description[MAXDESCR];
41 static struct sockaddr_un inpath;
43 static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int port, char *g, int m)
45 int pid = getpid();
46 struct request_v3 req;
47 int fdctl;
48 int gid;
49 struct group *gs;
50 struct passwd *callerpwd;
52 struct sockaddr_un sock;
54 callerpwd=getpwuid(getuid());
55 if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){
56 perror("socket");
57 exit(1);
59 sock.sun_family = AF_UNIX;
60 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s/ctl", name);
61 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
62 snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); /* FALLBACK TO VDE v1 */
63 if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){
64 perror("connect");
65 exit(1);
69 req.magic=SWITCH_MAGIC;
70 req.version=3;
71 req.type=REQ_NEW_CONTROL+((port > 0)?port << 8:0);
73 req.sock.sun_family=AF_UNIX;
74 snprintf(req.sock.sun_path, sizeof(req.sock.sun_path), "%s_%05d", name, pid);
75 memcpy(&inpath,&req.sock,sizeof(req.sock));
77 snprintf(req.description,MAXDESCR,"slirpvde user=%s PID=%d SOCK=%s",
78 callerpwd->pw_name,pid,req.sock.sun_path);
81 if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){
82 perror("bind");
83 exit(1);
86 if (send(fdctl,&req,sizeof(req)-MAXDESCR+strlen(req.description),0) < 0) {
87 perror("send");
88 exit(1);
91 if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) {
92 perror("recv");
93 exit(1);
96 if (g) {
97 if ((gs=getgrnam(g)) == NULL)
98 gid=atoi(g);
99 else
100 gid=gs->gr_gid;
101 chown(inpath.sun_path,-1,gid);
103 if (m>=0)
104 chmod(inpath.sun_path,m);
106 return fdctl;
109 static void cleanup(void)
111 unlink(inpath.sun_path);
114 static void sig_handler(int sig)
116 cleanup();
117 signal(sig, SIG_DFL);
118 kill(getpid(), sig);
121 static void setsighandlers()
123 /* setting signal handlers.
124 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
125 * ignores all the others signals which could cause termination. */
126 struct { int sig; const char *name; int ignore; } signals[] = {
127 { SIGHUP, "SIGHUP", 0 },
128 { SIGINT, "SIGINT", 0 },
129 { SIGPIPE, "SIGPIPE", 1 },
130 { SIGALRM, "SIGALRM", 1 },
131 { SIGTERM, "SIGTERM", 0 },
132 { SIGUSR1, "SIGUSR1", 1 },
133 { SIGUSR2, "SIGUSR2", 1 },
134 { SIGPOLL, "SIGPOLL", 1 },
135 { SIGPROF, "SIGPROF", 1 },
136 { SIGVTALRM, "SIGVTALRM", 1 },
137 { SIGSTKFLT, "SIGSTKFLT", 1 },
138 { SIGIO, "SIGIO", 1 },
139 { SIGPWR, "SIGPWR", 1 },
140 { SIGUNUSED, "SIGUNUSED", 1 },
141 { 0, NULL, 0 }
144 int i;
145 for(i = 0; signals[i].sig != 0; i++)
146 if(signal(signals[i].sig,
147 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
148 perror("Setting handler");
151 unsigned char bufin[BUFSIZE];
153 char *filename;
154 char numfd[10];
156 int slirp_can_output(void)
158 return 1;
161 static int fddata;
162 static struct sockaddr_un dataout;
164 #if 0
165 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
166 void dumppkt(const uint8_t *pkt, int pkt_len)
168 register int i,j;
169 printf("Packet dump len=%d\n",pkt_len);
170 if (pkt_len == 0)
171 return;
172 for (i=0;i<((pkt_len-1)/16)+1;i++) {
173 for (j=0;j<16;j++)
174 if (i*16+j > pkt_len)
175 printf(" ");
176 else
177 printf("%02x ",pkt[i*16+j]);
178 printf(" ");
179 for (j=0;j<16;j++)
180 if (i*16+j > pkt_len)
181 printf(" ");
182 else
183 printf("%c",convery2ascii(pkt[i*16+j]));
184 printf("\n");
187 #endif
189 void slirp_output(const uint8_t *pkt, int pkt_len)
191 /* slirp -> vde */
192 //fprintf(stderr,"RX from slirp %d\n",pkt_len);
193 //dumppkt(pkt,pkt_len);
194 sendto(fddata,pkt,pkt_len,0,(struct sockaddr *) &dataout, sizeof(struct sockaddr_un));
197 void usage(char *name) {
198 fprintf(stderr,"Usage: %s [-socket vdesock] [-dhcp] [-network netaddr] \n\t%s [-s vdesock] [-d] [-n netaddr]\n",name,name);
199 exit(-1);
202 struct option slirpvdeopts[] = {
203 {"socket",1,NULL,'s'},
204 {"sock",1,NULL,'s'},
205 {"vdesock",1,NULL,'s'},
206 {"unix",1,NULL,'s'},
207 {"dhcp",0,NULL,'d'},
208 {"network",0,NULL,'n'},
209 {"mod",1,0,'m'},
210 {"group",1,0,'g'},
211 {"port",1,0,'p'},
212 {NULL,0,0,0}};
214 int main(int argc, char **argv)
216 char *sockname;
217 struct sockaddr_un datain;
218 int datainsize;
219 int result,nfds;
220 int port=0;
221 int connected_fd;
222 register ssize_t nx;
223 register int i;
224 fd_set rs,ws,xs;
225 int opt,longindx;
226 char *netw=NULL;
227 char *group=NULL;
228 int mode=0700;
230 filename=basename(argv[0]);
231 sockname="/tmp/vde.ctl";
233 while ((opt=getopt_long_only(argc,argv,"s:n:p:g:m:d",slirpvdeopts,&longindx)) > 0) {
234 switch (opt) {
235 case 's' : sockname=optarg;
236 break;
237 case 'd' : dhcpmgmt = 1;
238 break;
239 case 'n' : netw=optarg;
240 break;
241 case 'm' : sscanf(optarg,"%o",&mode);
242 break;
243 case 'g' : group=strdup(optarg);
244 break;
245 case 'p' : port=atoi(optarg);
246 break;
247 default : usage(filename);
248 break;
251 atexit(cleanup);
253 if((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){
254 perror("socket");
255 exit(1);
257 connected_fd=send_fd(sockname, fddata, &dataout, port, group, mode);
258 slirp_init(netw);
260 for(;;) {
261 FD_ZERO(&rs);
262 FD_ZERO(&ws);
263 FD_ZERO(&xs);
264 nfds= -1;
265 slirp_select_fill(&nfds,&rs,&ws,&xs);
266 FD_SET(fddata,&rs);
267 FD_SET(connected_fd,&rs);
268 if (fddata>nfds) nfds=fddata;
269 if (connected_fd>nfds) nfds=connected_fd;
270 result=select(nfds+1,&rs,&ws,&xs,NULL);
271 //printf("SELECT %d %d\n",nfds,result);
272 if (FD_ISSET(connected_fd,&rs)) {
273 if(read(connected_fd,bufin,BUFSIZE)==0)
274 exit(0);
276 if (FD_ISSET(fddata,&rs)) {
277 nx=recvfrom(fddata,bufin,BUFSIZE,0,(struct sockaddr *) &datain, &datainsize);
278 //fprintf(stderr,"TX to slirp %d\n",nx);
279 result--;
280 slirp_input(bufin,nx);
281 //fprintf(stderr,"TX to slirp %d exit\n",nx);
283 if (result > 0) {
284 //fprintf(stderr,"slirp poll\n");
285 slirp_select_poll(&rs,&ws,&xs);
286 //fprintf(stderr,"slirp poll exit\n");
289 return(0);