1 /* Copyright 2003 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
16 #include <sys/ioctl.h>
17 #include <sys/socket.h>
21 #include <sys/types.h>
31 #define SWITCH_MAGIC 0xfeedface
36 static char *pidfile
= NULL
;
37 static char pidfile_path
[_POSIX_PATH_MAX
];
42 void printlog(int priority
, const char *format
, ...)
46 va_start (arg
, format
);
49 vsyslog(priority
,format
,arg
);
51 fprintf(stderr
,"%s: ",prog
);
52 vfprintf(stderr
,format
,arg
);
58 enum request_type
{ REQ_NEW_CONTROL
};
65 enum request_type type
;
66 struct sockaddr_un sock
;
67 char description
[MAXDESCR
];
70 static struct sockaddr_un inpath
;
72 static int send_fd(char *name
, int fddata
, struct sockaddr_un
*datasock
, int port
, char *g
, int m
)
75 struct request_v3 req
;
79 struct passwd
*callerpwd
;
81 struct sockaddr_un sock
;
83 callerpwd
=getpwuid(getuid());
84 if((fdctl
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0){
93 if(name
[strlen(name
)-1] == ']' && (split
=rindex(name
,'[')) != NULL
) {
97 if (*name
==0) name
=VDESTDSOCK
;
101 sock
.sun_family
= AF_UNIX
;
102 snprintf(sock
.sun_path
, sizeof(sock
.sun_path
), "%s/ctl", name
);
103 if(connect(fdctl
, (struct sockaddr
*) &sock
, sizeof(sock
))){
104 if (name
== VDESTDSOCK
) {
106 snprintf(sock
.sun_path
, sizeof(sock
.sun_path
), "%s/ctl", name
);
107 if(connect(fdctl
, (struct sockaddr
*) &sock
, sizeof(sock
))){
108 snprintf(sock
.sun_path
, sizeof(sock
.sun_path
), "%s", name
);
109 if(connect(fdctl
, (struct sockaddr
*) &sock
, sizeof(sock
))){
117 req
.magic
=SWITCH_MAGIC
;
119 req
.type
=REQ_NEW_CONTROL
+(port
<< 8);
120 req
.sock
.sun_family
=AF_UNIX
;
122 /* First choice, return socket from the switch close to the control dir*/
123 memset(req
.sock
.sun_path
, 0, sizeof(req
.sock
.sun_path
));
124 sprintf(req
.sock
.sun_path
, "%s.%05d-%02d", name
, pid
, 0);
125 if(bind(fddata
, (struct sockaddr
*) &req
.sock
, sizeof(req
.sock
)) < 0){
126 /* if it is not possible -> /tmp */
127 memset(req
.sock
.sun_path
, 0, sizeof(req
.sock
.sun_path
));
128 sprintf(req
.sock
.sun_path
, "/tmp/vde.%05d-%02d", pid
, 0);
129 if(bind(fddata
, (struct sockaddr
*) &req
.sock
, sizeof(req
.sock
)) < 0) {
135 snprintf(req
.description
,MAXDESCR
,"slirpvde user=%s PID=%d SOCK=%s",
136 callerpwd
->pw_name
,pid
,req
.sock
.sun_path
);
137 memcpy(&inpath
,&req
.sock
,sizeof(req
.sock
));
139 if (send(fdctl
,&req
,sizeof(req
)-MAXDESCR
+strlen(req
.description
),0) < 0) {
144 if (recv(fdctl
,datasock
,sizeof(struct sockaddr_un
),0)<0) {
150 if ((gs
=getgrnam(g
)) == NULL
)
154 chown(inpath
.sun_path
,-1,gid
);
157 chmod(inpath
.sun_path
,m
);
162 static void save_pidfile()
164 if(pidfile
[0] != '/')
165 strncat(pidfile_path
, pidfile
, PATH_MAX
- strlen(pidfile_path
));
167 strcpy(pidfile_path
, pidfile
);
169 int fd
= open(pidfile_path
,
170 O_WRONLY
| O_CREAT
| O_EXCL
,
171 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
175 printlog(LOG_ERR
, "Error in pidfile creation: %s", strerror(errno
));
179 if((f
= fdopen(fd
, "w")) == NULL
) {
180 printlog(LOG_ERR
, "Error in FILE* construction: %s", strerror(errno
));
184 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
185 printlog(LOG_ERR
, "Error in writing pidfile");
192 static void cleanup(void)
194 if((pidfile
!= NULL
) && unlink(pidfile_path
) < 0) {
195 printlog(LOG_WARNING
,"Couldn't remove pidfile '%s': %s", pidfile
, strerror(errno
));
197 unlink(inpath
.sun_path
);
200 static void sig_handler(int sig
)
203 signal(sig
, SIG_DFL
);
207 static void setsighandlers()
209 /* setting signal handlers.
210 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
211 * ignores all the others signals which could cause termination. */
212 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
213 { SIGHUP
, "SIGHUP", 0 },
214 { SIGINT
, "SIGINT", 0 },
215 { SIGPIPE
, "SIGPIPE", 1 },
216 { SIGALRM
, "SIGALRM", 1 },
217 { SIGTERM
, "SIGTERM", 0 },
218 { SIGUSR1
, "SIGUSR1", 1 },
219 { SIGUSR2
, "SIGUSR2", 1 },
220 { SIGPROF
, "SIGPROF", 1 },
221 { SIGVTALRM
, "SIGVTALRM", 1 },
223 { SIGPOLL
, "SIGPOLL", 1 },
224 { SIGSTKFLT
, "SIGSTKFLT", 1 },
225 { SIGIO
, "SIGIO", 1 },
226 { SIGPWR
, "SIGPWR", 1 },
227 { SIGUNUSED
, "SIGUNUSED", 1 },
230 { SIGXCPU
, "SIGXCPU", 1 },
231 { SIGXFSZ
, "SIGXFSZ", 1 },
237 for(i
= 0; signals
[i
].sig
!= 0; i
++)
238 if(signal(signals
[i
].sig
,
239 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
240 perror("Setting handler");
243 unsigned char bufin
[BUFSIZE
];
245 int slirp_can_output(void)
251 static struct sockaddr_un dataout
;
254 #define convery2ascii(x) ((x)>=' ' && (x) <= '~')?(x):'.'
255 void dumppkt(const uint8_t *pkt
, int pkt_len
)
258 printf("Packet dump len=%d\n",pkt_len
);
261 for (i
=0;i
<((pkt_len
-1)/16)+1;i
++) {
263 if (i
*16+j
> pkt_len
)
266 printf("%02x ",pkt
[i
*16+j
]);
269 if (i
*16+j
> pkt_len
)
272 printf("%c",convery2ascii(pkt
[i
*16+j
]));
278 void slirp_output(const uint8_t *pkt
, int pkt_len
)
281 //fprintf(stderr,"RX from slirp %d\n",pkt_len);
282 //dumppkt(pkt,pkt_len);
283 sendto(fddata
,pkt
,pkt_len
,0,(struct sockaddr
*) &dataout
, sizeof(struct sockaddr_un
));
298 struct redirtcp
*next
;
301 static struct redirtcp
*parse_redir_tcp(struct redirtcp
*head
, char *buff
)
306 char *ipaddrstr
=NULL
;
308 struct redirtcp
*new;
310 if ((ipaddrstr
= strchr(buff
, ':'))) {
312 if (*ipaddrstr
== 0) {
313 fprintf(stderr
,"redir TCP syntax error\n");
317 if ((portstr
= strchr(ipaddrstr
, ':'))) {
320 fprintf(stderr
,"redir TCP syntax error\n");
325 sscanf(buff
,"%d",&lport
);
326 sscanf(portstr
,"%d",&port
);
328 inaddr
= inet_addr(ipaddrstr
);
331 lprint(stderr
,"TCP redirection error: an IP address must be specified\r\n");
335 if ((new=malloc(sizeof(struct redirtcp
)))==NULL
)
346 static struct redirx
*parse_redir_x(struct redirx
*head
, char *buff
)
349 u_int32_t inaddr
= 0;
354 if ((ptr
= strchr(buff
, ':'))) {
357 fprintf(stderr
,"X-redirection syntax error\n");
362 inaddr
= inet_addr(buff
);
363 if (inaddr
== 0xffffffff) {
364 lprint(stderr
,"Error: X-redirection bad address\r\n");
369 if (strchr(ptr
, '.')) {
370 if (sscanf(ptr
, "%d.%d", &display
, &screen
) != 2)
373 if (sscanf(ptr
, "%d", &display
) != 1)
379 lprint(stderr
,"Error: X-redirection an IP address must be specified\r\n");
383 if ((new=malloc(sizeof(struct redirx
)))==NULL
)
387 new->display
=display
;
389 new->start_port
=start_port
;
395 static void do_redir_tcp(struct redirtcp
*head
)
398 do_redir_tcp(head
->next
);
399 redir_tcp(head
->inaddr
,head
->port
,head
->lport
);
404 static void do_redir_x(struct redirx
*head
)
407 do_redir_x(head
->next
);
408 redir_x(head
->inaddr
,head
->start_port
,head
->display
,head
->screen
);
413 void usage(char *name
) {
414 fprintf(stderr
,"Usage: %s [-socket vdesock] [-dhcp] [-daemon] [-network netaddr] \n\t%s [-s vdesock] [-D] [-d] [-n netaddr]\n",name
,name
);
418 struct option slirpvdeopts
[] = {
419 {"socket",1,NULL
,'s'},
421 {"vdesock",1,NULL
,'s'},
423 {"pidfile", 1, 0, 'p'},
425 {"daemon",0,NULL
,'d'},
426 {"network",0,NULL
,'n'},
432 int main(int argc
, char **argv
)
446 struct redirtcp
*rtcp
=NULL
;
447 struct redirx
*rx
=NULL
;
449 prog
=basename(argv
[0]);
451 while ((opt
=GETOPT_LONG(argc
,argv
,"s:n:p:g:m:L:X:dD",slirpvdeopts
,&longindx
)) > 0) {
453 case 's' : sockname
=optarg
;
455 case 'D' : dhcpmgmt
= 1;
457 case 'd' : daemonize
= 1;
459 case 'n' : netw
=optarg
;
461 case 'm' : sscanf(optarg
,"%o",&mode
);
463 case 'g' : group
=strdup(optarg
);
465 case 'p': pidfile
=strdup(optarg
);
467 case 'P' : port
=atoi(optarg
);
469 case 'L': rtcp
=parse_redir_tcp(rtcp
,optarg
);
471 case 'X': rx
=parse_redir_x(rx
,optarg
);
473 default : usage(prog
);
479 openlog(basename(prog
), LOG_PID
, 0);
481 syslog(LOG_INFO
,"slirpvde started");
483 if(getcwd(pidfile_path
, PATH_MAX
-1) == NULL
) {
484 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
487 strcat(pidfile_path
, "/");
488 if (daemonize
&& daemon(0, 1)) {
489 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
493 if((fddata
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) < 0){
497 connected_fd
=send_fd(sockname
, fddata
, &dataout
, port
, group
, mode
);
509 slirp_select_fill(&nfds
,&rs
,&ws
,&xs
);
511 FD_SET(connected_fd
,&rs
);
512 if (fddata
>nfds
) nfds
=fddata
;
513 if (connected_fd
>nfds
) nfds
=connected_fd
;
514 result
=select(nfds
+1,&rs
,&ws
,&xs
,NULL
);
515 //printf("SELECT %d %d\n",nfds,result);
516 if (FD_ISSET(fddata
,&rs
)) {
517 nx
=recv(fddata
,bufin
,BUFSIZE
,0);
518 //fprintf(stderr,"TX to slirp %d\n",nx);
520 slirp_input(bufin
,nx
);
521 //fprintf(stderr,"TX to slirp %d exit\n",nx);
524 //fprintf(stderr,"slirp poll\n");
525 slirp_select_poll(&rs
,&ws
,&xs
);
526 //fprintf(stderr,"slirp poll exit\n");
528 if (FD_ISSET(connected_fd
,&rs
)) {
529 if(read(connected_fd
,bufin
,BUFSIZE
)==0)