I forgot to delete a debugging printf
[vde.git] / vde-2 / vde_plug / vde_plug.c
blob37a38602aaed5807324c28376d0350f269411834
1 /* Copyright 2002 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
4 */
6 #include <config.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <signal.h>
10 #include <errno.h>
11 #include <unistd.h>
12 #include <stdint.h>
13 #include <getopt.h>
14 #include <string.h>
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
17 #include <sys/un.h>
18 #include <sys/uio.h>
19 #include <sys/poll.h>
20 #include <sys/utsname.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <pwd.h>
24 #include <grp.h>
25 #include <vde.h>
26 #include <libvdeplug/libvdeplug.h>
27 #ifdef VDE_IP_LOG
28 #define DO_SYSLOG
29 #endif
30 #ifdef DO_SYSLOG
31 #include <syslog.h>
32 #include <ctype.h>
33 #include <arpa/inet.h>
34 #endif
36 #ifndef MIN
37 #define MIN(X,Y) (((X)<(Y))?(X):(Y))
38 #endif
40 #define BUFSIZE 2048
41 #define ETH_ALEN 6
43 VDECONN *conn;
45 struct utsname me;
46 #define myname me.nodename
48 static struct passwd *callerpwd;
49 #ifdef DO_SYSLOG
50 static char host[256];
52 void write_syslog_entry(char *message)
54 char *ssh_client;
55 size_t ip_length;
57 openlog("vde_plug", 0, LOG_USER);
59 //get the caller IP address
60 //TNX Giordani-Macchia code from vish.c
61 if ((ssh_client=getenv("SSH_CLIENT"))!=NULL)
63 for (ip_length=0;ip_length<sizeof(host)&&ssh_client[ip_length]!=0&&!isspace(ssh_client[ip_length]);ip_length++);
64 if (ip_length>=sizeof(host))
65 ip_length=sizeof(host)-1;
66 memcpy(host,ssh_client,ip_length);
67 host[ip_length]=0;
69 else
70 strcpy(host,"UNKNOWN_IP_ADDRESS");
71 syslog(LOG_INFO,"%s: user %s IP %s",message,callerpwd->pw_name,host);
72 closelog();
75 void write_syslog_close()
77 write_syslog_entry("STOP");
79 #endif
81 #ifdef VDE_IP_LOG
82 #define MAX_IP 256
83 int vde_ip_log;
85 struct header {
86 unsigned char dest[ETH_ALEN];
87 unsigned char src[ETH_ALEN];
88 unsigned char proto[2];
91 union body {
92 struct {
93 unsigned char version;
94 unsigned char filler[11];
95 unsigned char ip4src[4];
96 unsigned char ip4dst[4];
97 } v4;
98 struct {
99 unsigned char version;
100 unsigned char filler[7];
101 unsigned char ip6src[16];
102 unsigned char ip6dst[16];
103 } v6;
104 struct {
105 unsigned char priovlan[2];
106 } vlan;
109 unsigned char ip4list[MAX_IP][4];
110 unsigned char ip6list[MAX_IP][16];
111 static unsigned char nulladdr[16];
113 static int hash4(unsigned char *addr)
115 return((addr[0]+2*addr[1]+3*addr[2]+5*addr[3]) % MAX_IP);
118 static int hash6(unsigned char *addr)
120 return((addr[0]+2*addr[1]+3*addr[2]+5*addr[3]+
121 7*addr[4]+11*addr[5]+13*addr[6]+17*addr[7]+
122 19*addr[8]+23*addr[9]+29*addr[10]+31*addr[11]+
123 37*addr[12]+41*addr[13]+43*addr[14]+47*addr[15]) % MAX_IP);
126 static void vde_ip_check(const unsigned char *buf,int rnx)
128 struct header *ph=(struct header *) buf;
129 register int i,j,vlan=0;
130 char addr[256];
131 union body *pb;
133 pb=(union body *)(ph+1);
134 if (ph->proto[0]==0x81 && ph->proto[1]==0x00) { /*VLAN*/
135 vlan=((pb->vlan.priovlan[0] << 8) + pb->vlan.priovlan[1]) & 0xfff;
136 pb=(union body *)(((char *)pb)+4);
138 if (ph->proto[0]==0x08 && ph->proto[1]==0x00 &&
139 pb->v4.version == 0x45) {
140 /*v4 */
141 i=hash4(pb->v4.ip4src);
142 j=(i+MAX_IP-1)%MAX_IP;
143 while (1) {
144 /* most frequent case first */
145 if (memcmp(pb->v4.ip4src,ip4list[i],4) == 0)
146 break;
147 else if (memcmp(ip4list[i],nulladdr,4) == 0) {
148 memcpy(ip4list[i],pb->v4.ip4src,4);
149 syslog(LOG_INFO,"user %s Real-IP %s has got VDE-IP4 %s on vlan %d",callerpwd->pw_name,host,inet_ntop(AF_INET,ip4list[i],addr,256),vlan);
150 /*new ipv4*/
151 break;
152 } else if (i==j) {
153 syslog(LOG_ERR,"IPv4 table full. Exiting\n");
154 /*full table*/
155 exit(-1);
156 } else
157 i= (i+1)%MAX_IP;
160 else if (ph->proto[0]==0x86 && ph->proto[1]==0xdd &&
161 pb->v4.version == 0x60) {
162 /* v6 */
163 i=hash6(pb->v6.ip6src);
164 j=(i+MAX_IP-1)%MAX_IP;
165 while (1) {
166 /* most frequent case first */
167 if (memcmp(pb->v6.ip6src,ip6list[i],16) == 0)
168 break;
169 else if (memcmp(ip6list[i],nulladdr,16) == 0) {
170 memcpy(ip6list[i],pb->v6.ip6src,16);
171 syslog(LOG_INFO,"user %s Real-IP %s has got VDE-IP6 %s on vlan %d",callerpwd->pw_name,host,inet_ntop(AF_INET6,ip6list[i],addr,256),vlan);
172 /*new ipv6*/
173 break;
174 } else if (i==j) {
175 syslog(LOG_ERR,"IPv6 table full. Exiting\n");
176 /*full table*/
177 exit(-1);
178 } else
179 i= (i+1)%MAX_IP;
183 #endif
185 unsigned char bufin[BUFSIZE];
187 void splitpacket(const unsigned char *buf,int size,VDECONN *conn)
189 static char fragment[BUFSIZE];
190 static char *fragp;
191 static unsigned int rnx,remaining;
193 //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",myname,rnx,remaining,size);
194 if (size==0) return;
195 if (rnx>0) {
196 register int amount=MIN(remaining,size);
197 //fprintf(stderr,"%s: fragment amount %d\n",myname,amount);
198 memcpy(fragp,buf,amount);
199 remaining-=amount;
200 fragp+=amount;
201 buf+=amount;
202 size-=amount;
203 if (remaining==0) {
204 //fprintf(stderr,"%s: delivered defrag %d\n",myname,rnx);
205 //send(fd,fragment,rnx,0);
206 #ifdef VDE_IP_LOG
207 if (vde_ip_log)
208 vde_ip_check(buf,rnx);
209 #endif
210 vde_send(conn,fragment,rnx,0);
211 rnx=0;
214 while (size > 0) {
215 rnx=(buf[0]<<8)+buf[1];
216 size-=2;
217 //fprintf(stderr,"%s %d: packet %d size %d %x %x\n",myname,getpid(),rnx,size,buf[0],buf[1]);
218 buf+=2;
219 if (rnx>1521) {
220 fprintf(stderr,"%s: Packet length error size %d rnx %d\n",myname,size,rnx);
221 rnx=0;
222 return;
224 if (rnx > size) {
225 //fprintf(stderr,"%s: begin defrag %d\n",myname,rnx);
226 fragp=fragment;
227 memcpy(fragp,buf,size);
228 remaining=rnx-size;
229 fragp+=size;
230 size=0;
231 } else {
232 //fprintf(stderr,"%s: deliver %d\n",myname,rnx);
233 //send(fd,buf,rnx,0);
234 #ifdef VDE_IP_LOG
235 if (vde_ip_log)
236 vde_ip_check(buf,rnx);
237 #endif
238 vde_send(conn,(char *)buf,rnx,0);
239 buf+=rnx;
240 size-=rnx;
241 rnx=0;
246 static void cleanup(void)
248 vde_close(conn);
251 static void sig_handler(int sig)
253 cleanup();
254 signal(sig, SIG_DFL);
255 kill(getpid(), sig);
258 static void setsighandlers()
260 /* setting signal handlers.
261 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
262 * ignores all the others signals which could cause termination. */
263 struct { int sig; const char *name; int ignore; } signals[] = {
264 { SIGHUP, "SIGHUP", 0 },
265 { SIGINT, "SIGINT", 0 },
266 { SIGPIPE, "SIGPIPE", 1 },
267 { SIGALRM, "SIGALRM", 1 },
268 { SIGTERM, "SIGTERM", 0 },
269 { SIGUSR1, "SIGUSR1", 1 },
270 { SIGUSR2, "SIGUSR2", 1 },
271 { SIGPROF, "SIGPROF", 1 },
272 { SIGVTALRM, "SIGVTALRM", 1 },
273 #ifdef VDE_LINUX
274 { SIGPOLL, "SIGPOLL", 1 },
275 { SIGSTKFLT, "SIGSTKFLT", 1 },
276 { SIGIO, "SIGIO", 1 },
277 { SIGPWR, "SIGPWR", 1 },
278 { SIGUNUSED, "SIGUNUSED", 1 },
279 #endif
280 #ifdef VDE_DARWIN
281 { SIGXCPU, "SIGXCPU", 1 },
282 { SIGXFSZ, "SIGXFSZ", 1 },
283 #endif
284 { 0, NULL, 0 }
287 int i;
288 for(i = 0; signals[i].sig != 0; i++)
289 if(signal(signals[i].sig,
290 signals[i].ignore ? SIG_IGN : sig_handler) < 0)
291 perror("Setting handler");
294 struct pollfd pollv[]={{STDIN_FILENO,POLLIN|POLLHUP},{0,POLLIN|POLLHUP},{0,POLLIN|POLLHUP}};
296 static void netusage() {
297 #ifdef DO_SYSLOG
298 write_syslog_entry("FAILED");
299 #endif
300 fprintf (stderr,"This is a Virtual Distributed Ethernet (vde) tunnel broker. \n"
301 "This is not a login shell, only vde_plug can be executed\n");
302 exit(-1);
305 static void usage(char *progname) {
306 fprintf (stderr,"Usage: %s [-p portnum] [-g group] [-m mod] socketname\n\n",progname);
307 exit(-1);
310 int main(int argc, char **argv)
312 static char *sockname=NULL;
313 int result;
314 register ssize_t nx;
315 struct vde_open_args open_args={.port=0,.group=NULL,.mode=0700};
317 uname(&me);
318 //get the login name
319 callerpwd=getpwuid(getuid());
321 if (argv[0][0] == '-')
322 netusage(); //implies exit
323 /* option parsing */
325 int c;
326 while (1) {
327 int option_index = 0;
329 static struct option long_options[] = {
330 {"sock", 1, 0, 's'},
331 {"vdesock", 1, 0, 's'},
332 {"unix", 1, 0, 's'},
333 {"port", 1, 0, 'p'},
334 {"help",0,0,'h'},
335 {"mod",1,0,'m'},
336 {"group",1,0,'g'},
337 {0, 0, 0, 0}
339 c = GETOPT_LONG (argc, argv, "hc:p:s:m:g:l",
340 long_options, &option_index);
341 if (c == -1)
342 break;
344 switch (c) {
345 case 'c':
346 if (strcmp(optarg,"vde_plug")==0) {
347 #ifdef DO_SYSLOG
348 write_syslog_entry("START");
349 atexit(write_syslog_close);
350 #ifdef VDE_IP_LOG
351 vde_ip_log=1;
352 #endif
353 #endif
356 else
357 netusage(); //implies exit
358 break;
360 case 'p':
361 open_args.port=atoi(optarg);
362 if (open_args.port <= 0 || open_args.port > 255 )
363 usage(argv[0]); //implies exit
364 break;
366 case 'h':
367 usage(argv[0]); //implies exit
368 break;
370 case 's':
371 sockname=strdup(optarg);
372 break;
374 case 'm':
375 sscanf(optarg,"%o",&(open_args.mode));
376 break;
378 case 'g':
379 open_args.group=strdup(optarg);
380 break;
382 case 'l':
383 #ifdef VDE_IP_LOG
384 write_syslog_entry("START");
385 atexit(write_syslog_close);
386 vde_ip_log=1;
387 break;
388 #endif
390 default:
391 usage(argv[0]); //implies exit
395 if (optind < argc && sockname==NULL)
396 sockname=argv[optind];
398 atexit(cleanup);
399 setsighandlers();
400 conn=vde_open(sockname,"vde_plug:",&open_args);
401 if (conn == NULL)
402 exit(1);
404 pollv[1].fd=vde_datafd(conn);
405 pollv[2].fd=vde_ctlfd(conn);
407 for(;;) {
408 result=poll(pollv,3,-1);
409 if ((pollv[0].revents | pollv[1].revents | pollv[2].revents) & POLLHUP ||
410 pollv[2].revents & POLLIN)
411 break;
412 if (pollv[0].revents & POLLIN) {
413 nx=read(STDIN_FILENO,bufin,sizeof(bufin));
414 /* if POLLIN but not data it means that the stream has been
415 * closed at the other end */
416 /*fprintf(stderr,"%s: RECV %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/
417 if (nx==0)
418 break;
419 splitpacket(bufin,nx,conn);
421 if (pollv[1].revents & POLLIN) {
422 nx=vde_recv(conn,(char *)(bufin+2),BUFSIZE-2,0);
423 if (nx<0)
424 perror("vde_plug: recvfrom ");
425 else
427 bufin[0]=nx >> 8;
428 bufin[1]=nx & 0xff;
429 write(STDOUT_FILENO,bufin,nx+2);
430 /*fprintf(stderr,"%s: SENT %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/
435 return(0);