1 /* Copyright 2002 Renzo Davoli
2 * Licensed under the GPL
3 * Modified by Ludovico Gardenghi 2005
15 #include <sys/ioctl.h>
16 #include <sys/socket.h>
20 #include <sys/utsname.h>
21 #include <sys/types.h>
26 #include <libvdeplug/libvdeplug.h>
33 #include <arpa/inet.h>
37 #define MIN(X,Y) (((X)<(Y))?(X):(Y))
46 #define myname me.nodename
48 static struct passwd
*callerpwd
;
50 static char host
[256];
52 void write_syslog_entry(char *message
)
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
);
70 strcpy(host
,"UNKNOWN_IP_ADDRESS");
71 syslog(LOG_INFO
,"%s: user %s IP %s",message
,callerpwd
->pw_name
,host
);
75 void write_syslog_close()
77 write_syslog_entry("STOP");
86 unsigned char dest
[ETH_ALEN
];
87 unsigned char src
[ETH_ALEN
];
88 unsigned char proto
[2];
93 unsigned char version
;
94 unsigned char filler
[11];
95 unsigned char ip4src
[4];
96 unsigned char ip4dst
[4];
99 unsigned char version
;
100 unsigned char filler
[7];
101 unsigned char ip6src
[16];
102 unsigned char ip6dst
[16];
105 unsigned char priovlan
[2];
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;
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) {
141 i
=hash4(pb
->v4
.ip4src
);
142 j
=(i
+MAX_IP
-1)%MAX_IP
;
144 /* most frequent case first */
145 if (memcmp(pb
->v4
.ip4src
,ip4list
[i
],4) == 0)
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
);
153 syslog(LOG_ERR
,"IPv4 table full. Exiting\n");
160 else if (ph
->proto
[0]==0x86 && ph
->proto
[1]==0xdd &&
161 pb
->v4
.version
== 0x60) {
163 i
=hash6(pb
->v6
.ip6src
);
164 j
=(i
+MAX_IP
-1)%MAX_IP
;
166 /* most frequent case first */
167 if (memcmp(pb
->v6
.ip6src
,ip6list
[i
],16) == 0)
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
);
175 syslog(LOG_ERR
,"IPv6 table full. Exiting\n");
185 unsigned char bufin
[BUFSIZE
];
187 void splitpacket(const unsigned char *buf
,int size
,VDECONN
*conn
)
189 static char fragment
[BUFSIZE
];
191 static unsigned int rnx
,remaining
;
193 //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",myname,rnx,remaining,size);
196 register int amount
=MIN(remaining
,size
);
197 //fprintf(stderr,"%s: fragment amount %d\n",myname,amount);
198 memcpy(fragp
,buf
,amount
);
204 //fprintf(stderr,"%s: delivered defrag %d\n",myname,rnx);
205 //send(fd,fragment,rnx,0);
208 vde_ip_check(buf
,rnx
);
210 vde_send(conn
,fragment
,rnx
,0);
215 rnx
=(buf
[0]<<8)+buf
[1];
217 //fprintf(stderr,"%s %d: packet %d size %d %x %x\n",myname,getpid(),rnx,size,buf[0],buf[1]);
220 fprintf(stderr
,"%s: Packet length error size %d rnx %d\n",myname
,size
,rnx
);
225 //fprintf(stderr,"%s: begin defrag %d\n",myname,rnx);
227 memcpy(fragp
,buf
,size
);
232 //fprintf(stderr,"%s: deliver %d\n",myname,rnx);
233 //send(fd,buf,rnx,0);
236 vde_ip_check(buf
,rnx
);
238 vde_send(conn
,(char *)buf
,rnx
,0);
246 static void cleanup(void)
251 static void sig_handler(int sig
)
254 signal(sig
, SIG_DFL
);
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 },
274 { SIGPOLL
, "SIGPOLL", 1 },
275 { SIGSTKFLT
, "SIGSTKFLT", 1 },
276 { SIGIO
, "SIGIO", 1 },
277 { SIGPWR
, "SIGPWR", 1 },
278 { SIGUNUSED
, "SIGUNUSED", 1 },
281 { SIGXCPU
, "SIGXCPU", 1 },
282 { SIGXFSZ
, "SIGXFSZ", 1 },
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() {
298 write_syslog_entry("FAILED");
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");
305 static void usage(char *progname
) {
306 fprintf (stderr
,"Usage: %s [-p portnum] [-g group] [-m mod] socketname\n\n",progname
);
310 int main(int argc
, char **argv
)
312 static char *sockname
=NULL
;
315 struct vde_open_args open_args
={.port
=0,.group
=NULL
,.mode
=0700};
319 callerpwd
=getpwuid(getuid());
321 if (argv
[0][0] == '-')
322 netusage(); //implies exit
327 int option_index
= 0;
329 static struct option long_options
[] = {
331 {"vdesock", 1, 0, 's'},
339 c
= GETOPT_LONG (argc
, argv
, "hc:p:s:m:g:l",
340 long_options
, &option_index
);
346 if (strcmp(optarg
,"vde_plug")==0) {
348 write_syslog_entry("START");
349 atexit(write_syslog_close
);
357 netusage(); //implies exit
361 open_args
.port
=atoi(optarg
);
362 if (open_args
.port
<= 0 || open_args
.port
> 255 )
363 usage(argv
[0]); //implies exit
367 usage(argv
[0]); //implies exit
371 sockname
=strdup(optarg
);
375 sscanf(optarg
,"%o",&(open_args
.mode
));
379 open_args
.group
=strdup(optarg
);
384 write_syslog_entry("START");
385 atexit(write_syslog_close
);
391 usage(argv
[0]); //implies exit
395 if (optind
< argc
&& sockname
==NULL
)
396 sockname
=argv
[optind
];
400 conn
=vde_open(sockname
,"vde_plug:",&open_args
);
404 pollv
[1].fd
=vde_datafd(conn
);
405 pollv
[2].fd
=vde_ctlfd(conn
);
408 result
=poll(pollv
,3,-1);
409 if ((pollv
[0].revents
| pollv
[1].revents
| pollv
[2].revents
) & POLLHUP
||
410 pollv
[2].revents
& POLLIN
)
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]);*/
419 splitpacket(bufin
,nx
,conn
);
421 if (pollv
[1].revents
& POLLIN
) {
422 nx
=vde_recv(conn
,(char *)(bufin
+2),BUFSIZE
-2,0);
424 perror("vde_plug: recvfrom ");
429 write(STDOUT_FILENO
,bufin
,nx
+2);
430 /*fprintf(stderr,"%s: SENT %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/