/* Copyright 2003 Renzo Davoli * Licensed under the GPL */ #include #include #include #include #include #ifndef __FreeBSD__ #include #endif #include #include #include #include #include #include #include #include #ifdef __FreeBSD__ #include #include #endif #define SWITCH_MAGIC 0xfeedface #define BUFSIZE 2048 #define ETH_ALEN 6 int dhcpmgmt=0; enum request_type { REQ_NEW_CONTROL }; struct request_v3 { uint32_t magic; uint32_t version; enum request_type type; struct sockaddr_un sock; }; #ifdef __FreeBSD__ #include "../vde.h" static char *data_socket = NULL; static void cleanup() { if(data_socket != NULL) unlink(data_socket); } static void sig_handler(int sig) { fprintf(stderr, "Caught signal %d, cleaning up and exiting\n", sig); cleanup(1,NULL); signal(sig, SIG_DFL); kill(getpid(), sig); } #endif static int send_fd(char *name, int fddata, struct sockaddr_un *datasock, int group) { int pid = getpid(); struct request_v3 req; int fdctl; struct sockaddr_un sock; #ifdef __FreeBSD__ struct timeval tv; #endif if((fdctl = socket(AF_UNIX, SOCK_STREAM, 0)) < 0){ perror("socket"); exit(1); } sock.sun_family = AF_UNIX; snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); if(connect(fdctl, (struct sockaddr *) &sock, sizeof(sock))){ perror("connect"); exit(1); } req.magic=SWITCH_MAGIC; req.version=3; req.type=REQ_NEW_CONTROL+((group > 0)?((geteuid()<<8) + group) << 8:0); req.sock.sun_family=AF_UNIX; memset(req.sock.sun_path, 0, sizeof(req.sock.sun_path)); #ifdef __FreeBSD__ gettimeofday(&tv, NULL); snprintf(req.sock.sun_path, sizeof(req.sock.sun_path), "%s.%i.%li", VDEDATSOCK, pid, tv.tv_usec); data_socket = strdup(req.sock.sun_path); #else sprintf(&req.sock.sun_path[1], "%5d", pid); #endif if(bind(fddata, (struct sockaddr *) &req.sock, sizeof(req.sock)) < 0){ perror("bind"); exit(1); } if (send(fdctl,&req,sizeof(req),0) < 0) { perror("send"); exit(1); } if (recv(fdctl,datasock,sizeof(struct sockaddr_un),0)<0) { perror("recv"); exit(1); } return fdctl; } unsigned char bufin[BUFSIZE]; struct pollfd pollv[]={{STDIN_FILENO,POLLIN|POLLHUP,0},{0,POLLIN|POLLHUP,0}}; char *filename; char numfd[10]; int slirp_can_output(void) { return 1; } static int fddata; static struct sockaddr_un dataout; #if 0 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.' void dumppkt(const uint8_t *pkt, int pkt_len) { register int i,j; printf("Packet dump len=%d\n",pkt_len); if (pkt_len == 0) return; for (i=0;i<((pkt_len-1)/16)+1;i++) { for (j=0;j<16;j++) if (i*16+j > pkt_len) printf(" "); else printf("%02x ",pkt[i*16+j]); printf(" "); for (j=0;j<16;j++) if (i*16+j > pkt_len) printf(" "); else printf("%c",convery2ascii(pkt[i*16+j])); printf("\n"); } } #endif void slirp_output(const uint8_t *pkt, int pkt_len) { /* slirp -> vde */ //fprintf(stderr,"RX from slirp %d\n",pkt_len); //dumppkt(pkt,pkt_len); sendto(fddata,pkt,pkt_len,0,(struct sockaddr *) &dataout, sizeof(struct sockaddr_un)); } void usage(char *name) { fprintf(stderr,"Usage: %s [-socket vdesock] [-dhcp] [-network netaddr] \n\t%s [-s vdesock] [-d] [-n netaddr]\n",name,name); exit(-1); } struct option slirpvdeopts[] = { {"socket",1,NULL,'s'}, {"sock",1,NULL,'s'}, {"vdesock",1,NULL,'s'}, {"unix",1,NULL,'s'}, {"dhcp",0,NULL,'d'}, {"network",0,NULL,'n'}, {NULL,0,0,0}}; int main(int argc, char **argv) { char *sockname; struct sockaddr_un datain; int datainsize; int result,nfds; int group=0; int connected_fd; register ssize_t nx; fd_set rs,ws,xs; int opt,longindx; char *netw=NULL; filename=basename(argv[0]); sockname="/tmp/vde.ctl"; while ((opt=getopt_long_only(argc,argv,"s:n:d",slirpvdeopts,&longindx)) > 0) { switch (opt) { case 's' : sockname=optarg; break; case 'd' : dhcpmgmt = 1; break; case 'n' : netw=optarg; break; default : usage(filename); break; } } if((fddata = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0){ perror("socket"); exit(1); } connected_fd=send_fd(sockname, fddata, &dataout, group); #ifdef __FreeBSD__ if(signal(SIGINT, sig_handler) < 0) { perror("signal"); } signal(SIGPIPE, SIG_IGN); /* FreeBSD 4.x sends SIGPIPE on reset sockets */ #endif slirp_init(netw); for(;;) { FD_ZERO(&rs); FD_ZERO(&ws); FD_ZERO(&xs); nfds= -1; slirp_select_fill(&nfds,&rs,&ws,&xs); FD_SET(fddata,&rs); if (fddata>nfds) nfds=fddata; result=select(nfds+1,&rs,&ws,&xs,NULL); //printf("SELECT %d %d\n",nfds,result); if (FD_ISSET(fddata,&rs)) { nx=recvfrom(fddata,bufin,BUFSIZE,0,(struct sockaddr *) &datain, &datainsize); //fprintf(stderr,"TX to slirp %d\n",nx); result--; slirp_input(bufin,nx); //fprintf(stderr,"TX to slirp %d exit\n",nx); } if (result > 0) { //fprintf(stderr,"slirp poll\n"); slirp_select_poll(&rs,&ws,&xs); //fprintf(stderr,"slirp poll exit\n"); } } return(0); }