1 /* Copyright 2002 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
14 #include <sys/ioctl.h>
15 #include <sys/socket.h>
18 #include <sys/utsname.h>
19 #include <sys/types.h>
26 #include <vdecommon.h>
27 #include <libvdeplug.h>
35 #include <arpa/inet.h>
39 #define MIN(X,Y) (((X)<(Y))?(X):(Y))
48 #define myname me.nodename
50 static struct passwd
*callerpwd
;
52 static char host
[256];
54 void write_syslog_entry(char *message
)
59 openlog("vde_plug", 0, LOG_USER
);
61 //get the caller IP address
62 //TNX Giordani-Macchia code from vish.c
63 if ((ssh_client
=getenv("SSH_CLIENT"))!=NULL
)
65 for (ip_length
=0;ip_length
<sizeof(host
)&&ssh_client
[ip_length
]!=0&&!isspace(ssh_client
[ip_length
]);ip_length
++);
66 if (ip_length
>=sizeof(host
))
67 ip_length
=sizeof(host
)-1;
68 memcpy(host
,ssh_client
,ip_length
);
72 strcpy(host
,"UNKNOWN_IP_ADDRESS");
73 syslog(LOG_INFO
,"%s: user %s IP %s",message
,callerpwd
->pw_name
,host
);
77 void write_syslog_close()
79 write_syslog_entry("STOP");
88 unsigned char dest
[ETH_ALEN
];
89 unsigned char src
[ETH_ALEN
];
90 unsigned char proto
[2];
95 unsigned char version
;
96 unsigned char filler
[11];
97 unsigned char ip4src
[4];
98 unsigned char ip4dst
[4];
101 unsigned char version
;
102 unsigned char filler
[7];
103 unsigned char ip6src
[16];
104 unsigned char ip6dst
[16];
107 unsigned char priovlan
[2];
111 unsigned char ip4list
[MAX_IP
][4];
112 unsigned char ip6list
[MAX_IP
][16];
113 static unsigned char nulladdr
[16];
115 static int hash4(unsigned char *addr
)
117 return((addr
[0]+2*addr
[1]+3*addr
[2]+5*addr
[3]) % MAX_IP
);
120 static int hash6(unsigned char *addr
)
122 return((addr
[0]+2*addr
[1]+3*addr
[2]+5*addr
[3]+
123 7*addr
[4]+11*addr
[5]+13*addr
[6]+17*addr
[7]+
124 19*addr
[8]+23*addr
[9]+29*addr
[10]+31*addr
[11]+
125 37*addr
[12]+41*addr
[13]+43*addr
[14]+47*addr
[15]) % MAX_IP
);
128 static void vde_ip_check(const unsigned char *buf
,int rnx
)
130 struct header
*ph
=(struct header
*) buf
;
131 register int i
,j
,vlan
=0;
135 pb
=(union body
*)(ph
+1);
136 if (ph
->proto
[0]==0x81 && ph
->proto
[1]==0x00) { /*VLAN*/
137 vlan
=((pb
->vlan
.priovlan
[0] << 8) + pb
->vlan
.priovlan
[1]) & 0xfff;
138 pb
=(union body
*)(((char *)pb
)+4);
140 if (ph
->proto
[0]==0x08 && ph
->proto
[1]==0x00 &&
141 pb
->v4
.version
== 0x45) {
143 i
=hash4(pb
->v4
.ip4src
);
144 j
=(i
+MAX_IP
-1)%MAX_IP
;
146 /* most frequent case first */
147 if (memcmp(pb
->v4
.ip4src
,ip4list
[i
],4) == 0)
149 else if (memcmp(ip4list
[i
],nulladdr
,4) == 0) {
150 memcpy(ip4list
[i
],pb
->v4
.ip4src
,4);
151 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
);
155 syslog(LOG_ERR
,"IPv4 table full. Exiting\n");
162 else if (ph
->proto
[0]==0x86 && ph
->proto
[1]==0xdd &&
163 pb
->v4
.version
== 0x60) {
165 i
=hash6(pb
->v6
.ip6src
);
166 j
=(i
+MAX_IP
-1)%MAX_IP
;
168 /* most frequent case first */
169 if (memcmp(pb
->v6
.ip6src
,ip6list
[i
],16) == 0)
171 else if (memcmp(ip6list
[i
],nulladdr
,16) == 0) {
172 memcpy(ip6list
[i
],pb
->v6
.ip6src
,16);
173 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
);
177 syslog(LOG_ERR
,"IPv6 table full. Exiting\n");
187 unsigned char bufin
[BUFSIZE
];
189 void splitpacket(const unsigned char *buf
,int size
,VDECONN
*conn
)
191 static char fragment
[BUFSIZE
];
193 static unsigned int rnx
,remaining
;
195 //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",myname,rnx,remaining,size);
198 register int amount
=MIN(remaining
,size
);
199 //fprintf(stderr,"%s: fragment amount %d\n",myname,amount);
200 memcpy(fragp
,buf
,amount
);
206 //fprintf(stderr,"%s: delivered defrag %d\n",myname,rnx);
207 //send(fd,fragment,rnx,0);
210 vde_ip_check(buf
,rnx
);
212 vde_send(conn
,fragment
,rnx
,0);
217 rnx
=(buf
[0]<<8)+buf
[1];
219 //fprintf(stderr,"%s %d: packet %d size %d %x %x\n",myname,getpid(),rnx,size,buf[0],buf[1]);
222 fprintf(stderr
,"%s: Packet length error size %d rnx %d\n",myname
,size
,rnx
);
227 //fprintf(stderr,"%s: begin defrag %d\n",myname,rnx);
229 memcpy(fragp
,buf
,size
);
234 //fprintf(stderr,"%s: deliver %d\n",myname,rnx);
235 //send(fd,buf,rnx,0);
238 vde_ip_check(buf
,rnx
);
240 vde_send(conn
,(char *)buf
,rnx
,0);
248 static void cleanup(void)
253 static void sig_handler(int sig
)
256 signal(sig
, SIG_DFL
);
260 static void setsighandlers()
262 /* setting signal handlers.
263 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
264 * ignores all the others signals which could cause termination. */
265 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
266 { SIGHUP
, "SIGHUP", 0 },
267 { SIGINT
, "SIGINT", 0 },
268 { SIGPIPE
, "SIGPIPE", 1 },
269 { SIGALRM
, "SIGALRM", 1 },
270 { SIGTERM
, "SIGTERM", 0 },
271 { SIGUSR1
, "SIGUSR1", 1 },
272 { SIGUSR2
, "SIGUSR2", 1 },
273 { SIGPROF
, "SIGPROF", 1 },
274 { SIGVTALRM
, "SIGVTALRM", 1 },
276 { SIGPOLL
, "SIGPOLL", 1 },
278 { SIGSTKFLT
, "SIGSTKFLT", 1 },
280 { SIGIO
, "SIGIO", 1 },
281 { SIGPWR
, "SIGPWR", 1 },
283 { SIGUNUSED
, "SIGUNUSED", 1 },
287 { SIGXCPU
, "SIGXCPU", 1 },
288 { SIGXFSZ
, "SIGXFSZ", 1 },
294 for(i
= 0; signals
[i
].sig
!= 0; i
++)
295 if(signal(signals
[i
].sig
,
296 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
297 perror("Setting handler");
300 struct pollfd pollv
[]={{STDIN_FILENO
,POLLIN
|POLLHUP
},{0,POLLIN
|POLLHUP
},{0,POLLIN
|POLLHUP
}};
302 static void netusage() {
304 write_syslog_entry("FAILED");
306 fprintf (stderr
,"This is a Virtual Distributed Ethernet (vde) tunnel broker. \n"
307 "This is not a login shell, only vde_plug can be executed\n");
311 static void usage(char *progname
) {
312 fprintf (stderr
,"Usage: %s [-p portnum] [-g group] [-m mod] socketname\n\n",progname
);
316 int main(int argc
, char **argv
)
318 static char *sockname
=NULL
;
321 struct vde_open_args open_args
={.port
=0,.group
=NULL
,.mode
=0700};
325 callerpwd
=getpwuid(getuid());
327 if (argv
[0][0] == '-')
328 netusage(); //implies exit
333 int option_index
= 0;
335 static struct option long_options
[] = {
337 {"vdesock", 1, 0, 's'},
345 c
= GETOPT_LONG (argc
, argv
, "hc:p:s:m:g:l",
346 long_options
, &option_index
);
352 if (strcmp(optarg
,"vde_plug")==0) {
354 write_syslog_entry("START");
355 atexit(write_syslog_close
);
363 netusage(); //implies exit
367 open_args
.port
=atoi(optarg
);
368 if (open_args
.port
<= 0 || open_args
.port
> 255 )
369 usage(argv
[0]); //implies exit
373 usage(argv
[0]); //implies exit
377 sockname
=strdup(optarg
);
381 sscanf(optarg
,"%o",&(open_args
.mode
));
385 open_args
.group
=strdup(optarg
);
390 write_syslog_entry("START");
391 atexit(write_syslog_close
);
397 usage(argv
[0]); //implies exit
401 if (optind
< argc
&& sockname
==NULL
)
402 sockname
=argv
[optind
];
406 conn
=vde_open(sockname
,"vde_plug:",&open_args
);
410 pollv
[1].fd
=vde_datafd(conn
);
411 pollv
[2].fd
=vde_ctlfd(conn
);
414 result
=poll(pollv
,3,-1);
415 if ((pollv
[0].revents
| pollv
[1].revents
| pollv
[2].revents
) & POLLHUP
||
416 pollv
[2].revents
& POLLIN
)
418 if (pollv
[0].revents
& POLLIN
) {
419 nx
=read(STDIN_FILENO
,bufin
,sizeof(bufin
));
420 /* if POLLIN but not data it means that the stream has been
421 * closed at the other end */
422 /*fprintf(stderr,"%s: RECV %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/
425 splitpacket(bufin
,nx
,conn
);
427 if (pollv
[1].revents
& POLLIN
) {
428 nx
=vde_recv(conn
,(char *)(bufin
+2),BUFSIZE
-2,0);
430 perror("vde_plug: recvfrom ");
435 write(STDOUT_FILENO
,bufin
,nx
+2);
436 /*fprintf(stderr,"%s: SENT %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/