2 * VDETELWEB: VDE telnet and WEB interface
6 * Copyright 2005,2008 Virtual Square Team University of Bologna - Italy
7 * 2005 written by Renzo Davoli
8 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004
9 * (copied from vde_switch code).
10 * 2008 updated Renzo Davoli
11 * 2008 sha1sum by Marco Dalla Via
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License along
24 * with this program; if not, write to the Free Software Foundation, Inc.,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/select.h>
45 #include <sys/utsname.h>
47 #include <netinet/in.h>
48 #include <arpa/inet.h>
53 #include "vdetelweb.h"
67 static char *pidfile
= NULL
;
68 static char pidfile_path
[_POSIX_PATH_MAX
];
69 struct stack
*lwipstack
;
74 struct pollfd pfd
[MAXFD
];
78 #define ROOTCONFFILE "/etc/vde/vdetelwebrc"
80 /* This will be prefixed by getenv("HOME") */
81 #define USERCONFFILE "/.vde/vdetelwebrc"
83 void printlog(int priority
, const char *format
, ...)
87 va_start (arg
, format
);
90 vsyslog(priority
,format
,arg
);
92 fprintf(stderr
,"%s: ",progname
);
93 vfprintf(stderr
,format
,arg
);
100 static void cleanup(void)
103 lwip_stack_free(lwipstack
);
104 if((pidfile
!= NULL
) && unlink(pidfile_path
) < 0) {
105 printlog(LOG_WARNING
,"Couldn't remove pidfile '%s': %s", pidfile
, strerror(errno
));
109 static char hex
[]="0123456789abcdef";
110 int sha1passwdok(const char *pw
) {
111 unsigned char out
[mhash_get_block_size(MHASH_SHA1
)];
112 char outstr
[mhash_get_block_size(MHASH_SHA1
)*2+1];
115 td
=mhash_init(MHASH_SHA1
);
116 mhash(td
, pw
, strlen(pw
));
117 mhash_deinit(td
, out
);
118 for (i
=0; i
<mhash_get_block_size(MHASH_SHA1
); i
++) {
119 outstr
[2*i
]=hex
[out
[i
] >> 4];
120 outstr
[2*i
+1]=hex
[out
[i
] & 0xf];
123 return (memcmp(outstr
,passwd
,mhash_get_block_size(MHASH_SHA1
))==0);
126 static void sig_handler(int sig
)
129 signal(sig
, SIG_DFL
);
133 static void setsighandlers(void)
135 /* setting signal handlers.
136 * * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
137 * * ignores all the others signals which could cause termination. */
138 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
139 { SIGHUP
, "SIGHUP", 0 },
140 { SIGINT
, "SIGINT", 0 },
141 { SIGPIPE
, "SIGPIPE", 1 },
142 { SIGALRM
, "SIGALRM", 1 },
143 { SIGTERM
, "SIGTERM", 0 },
144 { SIGUSR1
, "SIGUSR1", 1 },
145 { SIGUSR2
, "SIGUSR2", 1 },
146 { SIGPOLL
, "SIGPOLL", 1 },
147 { SIGPROF
, "SIGPROF", 1 },
148 { SIGVTALRM
, "SIGVTALRM", 1 },
150 { SIGSTKFLT
, "SIGSTKFLT", 1 },
152 { SIGIO
, "SIGIO", 1 },
153 { SIGPWR
, "SIGPWR", 1 },
155 { SIGUNUSED
, "SIGUNUSED", 1 },
161 for(i
= 0; signals
[i
].sig
!= 0; i
++)
162 if(signal(signals
[i
].sig
,
163 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
164 perror("Setting handler");
167 static void usage(char *progname
) {
168 fprintf (stderr
,"Usage: %s [-w] [-t] [-d] [-n nodename] [-p pidfile] mgmt_socket\n"
169 " %s [--web] [--telnet] [--daemon] [--nodename nodename] [--pidfile pidfile] mgmt_socket\n",progname
,progname
);
173 void setprompt(char *ctrl
,char *nodename
)
176 if (nodename
==NULL
) {
179 snprintf(buf
,BUFSIZE
,"VDE2@%s[%s]: ",un
.nodename
,ctrl
);
181 snprintf(buf
,BUFSIZE
,"VDE2@%s[%s]: ",nodename
,ctrl
);
185 int openextravdem(void)
187 struct sockaddr_un sun
;
190 sun
.sun_family
=PF_UNIX
;
191 snprintf(sun
.sun_path
,UNIX_PATH_MAX
,"%s",mgmt
);
192 fd
=socket(PF_UNIX
,SOCK_STREAM
,0);
193 if (connect(fd
,(struct sockaddr
*)(&sun
),sizeof(sun
)) < 0) {
194 printlog(LOG_ERR
,"Error connecting to the management socket '%s': %s", mgmt
, strerror(errno
));
197 if ((n
=read(fd
,buf
,BUFSIZE
))<=0) {
198 printlog(LOG_ERR
,"banner %s",strerror(errno
));
204 int openvdem(char *mgmt
,char *progname
, struct netif
**nif
,char *nodename
)
206 struct sockaddr_un sun
;
208 char buf
[BUFSIZE
+1],*line2
,*ctrl
;
209 sun
.sun_family
=PF_UNIX
;
210 snprintf(sun
.sun_path
,UNIX_PATH_MAX
,"%s",mgmt
);
211 fd
=socket(PF_UNIX
,SOCK_STREAM
,0);
212 if (connect(fd
,(struct sockaddr
*)(&sun
),sizeof(sun
)) < 0) {
213 printlog(LOG_ERR
,"Error connecting to the management socket '%s': %s", mgmt
, strerror(errno
));
216 if ((n
=read(fd
,buf
,BUFSIZE
))<=0) {
217 printlog(LOG_ERR
,"Error reading banner from VDE switch: %s",strerror(errno
));
221 if ((ctrl
=rindex(buf
,'\n')) != NULL
)
224 write(fd
,"ds/showinfo\n",12);
225 if ((n
=read(fd
,buf
,BUFSIZE
))<=0) {
226 printlog(LOG_ERR
,"Error reading ctl socket from VDE switch: %s",strerror(errno
));
230 if ((line2
=index(buf
,'\n')) == NULL
) {
231 printlog(LOG_ERR
,"Error parsing first line of ctl socket information");
235 if (strncmp(line2
,"ctl dir ",8) != 0) {
236 printlog(LOG_ERR
,"Error parsing ctl socket information");
239 for(ctrl
=line2
+8;*ctrl
!='\n' && ctrl
<buf
+n
;ctrl
++)
243 setprompt(ctrl
,nodename
);
245 *nif
=lwip_vdeif_add(lwipstack
,ctrl
);
247 printlog(LOG_ERR
,"Cannot connect to the VDE switch");
255 static void bitno2mask(unsigned char *addr
,int bitno
,int len
)
258 for(i
=0;i
<len
;i
++,bitno
-= 8) {
264 addr
[i
]=256 - (1<<(8-bitno
));
268 static void sockaddr2ip_6addr(struct ip_addr
*ipaddrp
,unsigned char *addr
)
271 (addr
[0]<<8)|addr
[1],
272 (addr
[2]<<8)|addr
[3],
273 (addr
[4]<<8)|addr
[5],
274 (addr
[6]<<8)|addr
[7],
275 (addr
[8]<<8)|addr
[9],
276 (addr
[10]<<8)|addr
[11],
277 (addr
[12]<<8)|addr
[13],
278 (addr
[14]<<8)|addr
[15]);
281 static void readip(char *arg
,struct netif
*nif
,int af
)
283 char *bit
=rindex(arg
,'/');
285 printlog(LOG_ERR
,"IP addresses must include the netmask i.e. addr/maskbits");
287 int bitno
=atoi(bit
+1);
289 struct addrinfo
*res
,hint
;
290 struct ip_addr ipaddr
,netmask
;
292 memset(&hint
,0,sizeof(hint
));
294 if ((err
=getaddrinfo(arg
,NULL
,&hint
,&res
))!=0)
295 printlog(LOG_ERR
,"IP address %s error %s",arg
,gai_strerror(err
));
297 switch(res
->ai_family
) {
300 struct sockaddr_in
*in
=(struct sockaddr_in
*)res
->ai_addr
;
301 int addrh
=ntohl(in
->sin_addr
.s_addr
);
302 unsigned char i
,addr
[4];
303 for (i
=0;i
<4;i
++,addrh
>>=8)
305 IP64_ADDR(&ipaddr
, addr
[0],addr
[1],addr
[2],addr
[3]);
306 bitno2mask(addr
,bitno
,4);
307 IP64_MASKADDR(&netmask
, addr
[0],addr
[1],addr
[2],addr
[3]);
308 lwip_add_addr(nif
,&ipaddr
,&netmask
);
313 struct sockaddr_in6
*in
=(struct sockaddr_in6
*)res
->ai_addr
;
314 unsigned char *addr
=in
->sin6_addr
.s6_addr
;
315 sockaddr2ip_6addr(&ipaddr
,addr
);
316 bitno2mask(addr
,bitno
,16);
317 sockaddr2ip_6addr(&netmask
,addr
);
318 lwip_add_addr(nif
,&ipaddr
,&netmask
);
322 printlog(LOG_ERR
,"Unsupported Address Family: %s",arg
);
329 static void readdefroute(char *arg
,struct netif
*nif
,int af
)
331 struct addrinfo
*res
,hint
;
332 struct ip_addr ipaddr
;
334 memset(&hint
,0,sizeof(hint
));
336 if ((err
=getaddrinfo(arg
,NULL
,&hint
,&res
))!=0)
337 printlog(LOG_ERR
,"IP address %s error %s",arg
,gai_strerror(err
));
339 switch(res
->ai_family
) {
342 struct sockaddr_in
*in
=(struct sockaddr_in
*)res
->ai_addr
;
343 int addrh
=ntohl(in
->sin_addr
.s_addr
);
344 unsigned char i
,addr
[4];
345 for (i
=0;i
<4;i
++,addrh
>>=8)
347 IP64_ADDR(&ipaddr
, addr
[0],addr
[1],addr
[2],addr
[3]);
348 lwip_add_route(lwipstack
,IP_ADDR_ANY
,IP_ADDR_ANY
,&ipaddr
,nif
,0);
353 struct sockaddr_in6
*in
=(struct sockaddr_in6
*)res
->ai_addr
;
354 sockaddr2ip_6addr(&ipaddr
,in
->sin6_addr
.s6_addr
);
355 lwip_add_route(lwipstack
,IP_ADDR_ANY
,IP_ADDR_ANY
,&ipaddr
,nif
,0);
359 printlog(LOG_ERR
,"Unsupported Address Family: %s",arg
);
365 static void readpassword(char *arg
,int unused
)
375 {"ip4",readip
,PF_INET
},
376 {"ip6",readip
,PF_INET6
},
378 {"defroute4",readdefroute
,PF_INET
},
379 {"defroute6",readdefroute
,PF_INET6
},
380 {"defroute",readdefroute
,0},
381 {"password",readpassword
,0},
384 int readconffile(char *path
,struct netif
*nif
)
387 char buf
[BUFSIZE
],*s
;
392 if((f
=fopen(path
,"r"))==NULL
)
394 while (fgets(buf
,BUFSIZE
,f
) != NULL
)
398 if ((s
=rindex(buf
,'\n')) != NULL
)
401 for(s
=buf
;*s
== ' ' || *s
== '\t';s
++);
403 if (*s
!= '#' && *s
!= '\n' && *s
!= '\0')
406 for (scf
=cft
;scf
->tag
!= NULL
;scf
++)
407 if(strncmp(s
,scf
->tag
,strlen(scf
->tag
)) == 0)
410 for(;*s
== ' ' || *s
== '\t';s
++);
413 for(;*s
== ' ' || *s
== '\t';s
++);
414 scf
->f(s
,nif
,scf
->arg
);
417 if (scf
->tag
== NULL
)
418 printlog(LOG_ERR
,"Error parsing configuration file: line %d: %s", line
, buf
);
424 int addpfd(int fd
,voidfun cb
)
428 pfd
[npfd
].events
=POLLIN
|POLLHUP
;
439 for (i
=fn
;i
<npfd
-1;i
++) {
442 status
[i
]=status
[i
+1];
447 int pfdsearch(int fd
)
450 for (i
=0;i
<npfd
&& pfd
[i
].fd
!=fd
;i
++)
456 int setfds(fd_set
*rds
, fd_set
*exc
)
461 for (i
=0;i
<npfd
;i
++) {
462 FD_SET(pfd
[i
].fd
,rds
);
463 FD_SET(pfd
[i
].fd
,exc
);
464 if (pfd
[i
].fd
>max
) max
=pfd
[i
].fd
;
470 static void save_pidfile(void)
472 if(pidfile
[0] != '/')
473 strncat(pidfile_path
, pidfile
, _POSIX_PATH_MAX
- strlen(pidfile_path
));
475 strcpy(pidfile_path
, pidfile
);
477 int fd
= open(pidfile_path
,
478 O_WRONLY
| O_CREAT
| O_EXCL
,
479 S_IRUSR
| S_IWUSR
| S_IRGRP
| S_IROTH
);
483 printlog(LOG_ERR
, "Error in pidfile creation: %s", strerror(errno
));
487 if((f
= fdopen(fd
, "w")) == NULL
) {
488 printlog(LOG_ERR
, "Error in FILE* construction: %s", strerror(errno
));
492 if(fprintf(f
, "%ld\n", (long int)getpid()) <= 0) {
493 printlog(LOG_ERR
, "Error in writing pidfile");
500 /* this custom version of daemon(3) continue to receive stderr messages
501 * until the end of the startup phase, the foreground process terminates
502 * when stderr gets closed*/
503 static int special_daemon(void)
520 while ((n
=read(errorpipe
[0],buf
,128)) > 0) {
521 write(STDERR_FILENO
,buf
,n
);
532 if ((fd
= open("/dev/null", O_RDWR
, 0)) != -1) {
533 (void)dup2(fd
, STDIN_FILENO
);
534 (void)dup2(fd
, STDOUT_FILENO
);
535 (void)dup2(errorpipe
[1], STDERR_FILENO
);
543 int main(int argc
, char *argv
[])
554 int option_index
= 0;
556 static struct option long_options
[] = {
557 {"daemon", 0, 0, 'd'},
559 {"telnet", 0, 0, 't'},
563 {"nodename",1,0,'n'},
564 {"pidfile", 1, 0, 'p'},
567 c
= getopt_long_only (argc
, argv
, "hdwtM:f:n:",
568 long_options
, &option_index
);
577 conffile
=strdup(optarg
);
580 nodename
=strdup(optarg
);
592 pidfile
=strdup(optarg
);
595 usage(argv
[0]); //implies exit
599 if (optind
< argc
&& mgmt
==NULL
)
603 printlog(LOG_ERR
,"mgmt_socket not defined");
606 if (telnet
==0 && web
==0) {
607 printlog(LOG_ERR
,"at least one service option (-t -w) must be specified");
614 /* saves current path in pidfile_path, because otherwise with daemonize() we
616 if(getcwd(pidfile_path
, _POSIX_PATH_MAX
-1) == NULL
) {
617 printlog(LOG_ERR
, "getcwd: %s", strerror(errno
));
620 strcat(pidfile_path
, "/");
622 /* call daemon before starting the stack otherwise the stack threads
623 * does not get inherited by the forked process */
624 if (daemonize
&& special_daemon()) {
625 printlog(LOG_ERR
,"daemon: %s",strerror(errno
));
629 lwipstack
=lwip_stack_new();
630 lwip_stack_set(lwipstack
);
632 vdefd
= openvdem(mgmt
, argv
[0], &nif
, nodename
);
634 /* If rcfile is specified, try it and nothing else */
635 if (conffile
&& readconffile(conffile
,nif
) < 0)
637 printlog(LOG_ERR
, "Error reading configuration file '%s': %s", conffile
, strerror(errno
));
640 /* Else try default ones */
644 char *homedir
= getenv("HOME");
647 int len
= strlen(homedir
) + strlen(USERCONFFILE
) + 1;
648 conffile
= malloc(len
);
649 snprintf(conffile
, len
, "%s%s", homedir
, USERCONFFILE
);
650 if ((rv
= readconffile(conffile
, nif
)) >= 0)
653 if (!homedir
|| rv
< 0)
654 rv
= readconffile(conffile
= ROOTCONFFILE
, nif
);
658 printlog(LOG_ERR
, "Error reading configuration file '%s': %s", conffile
, strerror(errno
));
663 /* once here, we're sure we're the true process which will continue as a
664 * server: save PID file if needed */
665 if(pidfile
) save_pidfile();
674 if ((fd
=open("/dev/null",O_RDWR
)) >= 0) {
675 close(STDERR_FILENO
);
676 dup2(fd
,STDERR_FILENO
);
678 openlog(basename(argv
[0]), LOG_PID
, 0);
681 printlog(LOG_INFO
,"VDETELWEB started");
687 int m
=lwip_poll(pfd
,npfd
,-1);
688 for (i
=0;i
<npfd
&& m
>0;i
++) {
689 if (pfd
[i
].revents
) {
691 fpfd
[i
](i
,pfd
[i
].fd
,vdefd
);