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>
27 #include <vdecommon.h>
28 #include <libvdeplug.h>
36 #include <arpa/inet.h>
40 #define MIN(X,Y) (((X)<(Y))?(X):(Y))
50 #define myname me.nodename
52 static struct passwd
*callerpwd
;
54 static char host
[256];
56 void write_syslog_entry(char *message
)
61 openlog("vde_plug", 0, LOG_USER
);
63 //get the caller IP address
64 //TNX Giordani-Macchia code from vish.c
65 if ((ssh_client
=getenv("SSH_CLIENT"))!=NULL
)
67 for (ip_length
=0;ip_length
<sizeof(host
)&&ssh_client
[ip_length
]!=0&&!isspace(ssh_client
[ip_length
]);ip_length
++);
68 if (ip_length
>=sizeof(host
))
69 ip_length
=sizeof(host
)-1;
70 memcpy(host
,ssh_client
,ip_length
);
74 strcpy(host
,"UNKNOWN_IP_ADDRESS");
75 syslog(LOG_INFO
,"%s: user %s IP %s",message
,callerpwd
->pw_name
,host
);
79 void write_syslog_close()
81 write_syslog_entry("STOP");
90 unsigned char dest
[ETH_ALEN
];
91 unsigned char src
[ETH_ALEN
];
92 unsigned char proto
[2];
97 unsigned char version
;
98 unsigned char filler
[11];
99 unsigned char ip4src
[4];
100 unsigned char ip4dst
[4];
103 unsigned char version
;
104 unsigned char filler
[7];
105 unsigned char ip6src
[16];
106 unsigned char ip6dst
[16];
109 unsigned char priovlan
[2];
113 unsigned char ip4list
[MAX_IP
][4];
114 unsigned char ip6list
[MAX_IP
][16];
115 static unsigned char nulladdr
[16];
117 static int hash4(unsigned char *addr
)
119 return((addr
[0]+2*addr
[1]+3*addr
[2]+5*addr
[3]) % MAX_IP
);
122 static int hash6(unsigned char *addr
)
124 return((addr
[0]+2*addr
[1]+3*addr
[2]+5*addr
[3]+
125 7*addr
[4]+11*addr
[5]+13*addr
[6]+17*addr
[7]+
126 19*addr
[8]+23*addr
[9]+29*addr
[10]+31*addr
[11]+
127 37*addr
[12]+41*addr
[13]+43*addr
[14]+47*addr
[15]) % MAX_IP
);
130 static void vde_ip_check(const unsigned char *buf
,int rnx
)
132 struct header
*ph
=(struct header
*) buf
;
137 pb
=(union body
*)(ph
+1);
138 if (ph
->proto
[0]==0x81 && ph
->proto
[1]==0x00) { /*VLAN*/
139 vlan
=((pb
->vlan
.priovlan
[0] << 8) + pb
->vlan
.priovlan
[1]) & 0xfff;
140 pb
=(union body
*)(((char *)pb
)+4);
142 if (ph
->proto
[0]==0x08 && ph
->proto
[1]==0x00 &&
143 pb
->v4
.version
== 0x45) {
145 i
=hash4(pb
->v4
.ip4src
);
146 j
=(i
+MAX_IP
-1)%MAX_IP
;
148 /* most frequent case first */
149 if (memcmp(pb
->v4
.ip4src
,ip4list
[i
],4) == 0)
151 else if (memcmp(ip4list
[i
],nulladdr
,4) == 0) {
152 memcpy(ip4list
[i
],pb
->v4
.ip4src
,4);
153 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
);
157 syslog(LOG_ERR
,"IPv4 table full. Exiting\n");
164 else if (ph
->proto
[0]==0x86 && ph
->proto
[1]==0xdd &&
165 pb
->v4
.version
== 0x60) {
167 i
=hash6(pb
->v6
.ip6src
);
168 j
=(i
+MAX_IP
-1)%MAX_IP
;
170 /* most frequent case first */
171 if (memcmp(pb
->v6
.ip6src
,ip6list
[i
],16) == 0)
173 else if (memcmp(ip6list
[i
],nulladdr
,16) == 0) {
174 memcpy(ip6list
[i
],pb
->v6
.ip6src
,16);
175 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
);
179 syslog(LOG_ERR
,"IPv6 table full. Exiting\n");
189 void vdeplug_err(void *opaque
, int type
, char *format
,...)
193 if (isatty(STDERR_FILENO
)) {
194 fprintf(stderr
, "%s: Packet length error",myname
);
195 va_start(args
, format
);
196 vfprintf(stderr
, format
, args
);
198 fprintf(stderr
,"\n");
202 ssize_t
vdeplug_recv(void *opaque
, void *buf
, size_t count
)
204 VDECONN
*conn
=opaque
;
207 vde_ip_check(buf
,count
);
209 return vde_send(conn
,(char *)buf
,count
,0);
212 static void cleanup(void)
214 vdestream_close(vdestream
);
218 static void sig_handler(int sig
)
221 signal(sig
, SIG_DFL
);
228 static void setsighandlers()
230 /* setting signal handlers.
231 * sets clean termination for SIGHUP, SIGINT and SIGTERM, and simply
232 * ignores all the others signals which could cause termination. */
233 struct { int sig
; const char *name
; int ignore
; } signals
[] = {
234 { SIGHUP
, "SIGHUP", 0 },
235 { SIGINT
, "SIGINT", 0 },
236 { SIGPIPE
, "SIGPIPE", 1 },
237 { SIGALRM
, "SIGALRM", 1 },
238 { SIGTERM
, "SIGTERM", 0 },
239 { SIGUSR1
, "SIGUSR1", 1 },
240 { SIGUSR2
, "SIGUSR2", 1 },
241 { SIGPROF
, "SIGPROF", 1 },
242 { SIGVTALRM
, "SIGVTALRM", 1 },
244 { SIGPOLL
, "SIGPOLL", 1 },
246 { SIGSTKFLT
, "SIGSTKFLT", 1 },
248 { SIGIO
, "SIGIO", 1 },
249 { SIGPWR
, "SIGPWR", 1 },
251 { SIGUNUSED
, "SIGUNUSED", 1 },
255 { SIGXCPU
, "SIGXCPU", 1 },
256 { SIGXFSZ
, "SIGXFSZ", 1 },
262 for(i
= 0; signals
[i
].sig
!= 0; i
++)
263 if(signal(signals
[i
].sig
,
264 signals
[i
].ignore
? SIG_IGN
: sig_handler
) < 0)
265 perror("Setting handler");
268 struct pollfd pollv
[]={{STDIN_FILENO
,POLLIN
|POLLHUP
},{0,POLLIN
|POLLHUP
},{0,POLLIN
|POLLHUP
}};
270 static void netusage() {
272 write_syslog_entry("FAILED");
274 fprintf (stderr
,"This is a Virtual Distributed Ethernet (vde) tunnel broker. \n"
275 "This is not a login shell, only vde_plug can be executed\n");
279 static void usage(char *progname
) {
280 fprintf (stderr
,"Usage: %s [-p portnum] [-g group] [-m mod] socketname\n\n",progname
);
284 unsigned char bufin
[BUFSIZE
];
286 int main(int argc
, char **argv
)
288 static char *sockname
=NULL
;
290 struct vde_open_args open_args
={.port
=0,.group
=NULL
,.mode
=0700};
294 callerpwd
=getpwuid(getuid());
296 if (argv
[0][0] == '-')
297 netusage(); //implies exit
302 int option_index
= 0;
304 static struct option long_options
[] = {
306 {"vdesock", 1, 0, 's'},
314 c
= GETOPT_LONG (argc
, argv
, "hc:p:s:m:g:l",
315 long_options
, &option_index
);
321 if (strcmp(optarg
,"vde_plug")==0) {
323 write_syslog_entry("START");
324 atexit(write_syslog_close
);
332 netusage(); //implies exit
336 open_args
.port
=atoi(optarg
);
337 if (open_args
.port
<= 0)
338 usage(argv
[0]); //implies exit
342 usage(argv
[0]); //implies exit
346 sockname
=strdup(optarg
);
350 sscanf(optarg
,"%o",(unsigned int *)&(open_args
.mode
));
354 open_args
.group
=strdup(optarg
);
359 write_syslog_entry("START");
360 atexit(write_syslog_close
);
366 usage(argv
[0]); //implies exit
370 if (optind
< argc
&& sockname
==NULL
)
371 sockname
=argv
[optind
];
375 conn
=vde_open(sockname
,"vde_plug:",&open_args
);
377 fprintf(stderr
,"vde_open %s: %s\n",sockname
?sockname
:"DEF_SWITCH",strerror(errno
));
381 vdestream
=vdestream_open(conn
,STDOUT_FILENO
,vdeplug_recv
,vdeplug_err
);
383 pollv
[1].fd
=vde_datafd(conn
);
384 pollv
[2].fd
=vde_ctlfd(conn
);
388 if ((pollv
[0].revents
| pollv
[1].revents
| pollv
[2].revents
) & POLLHUP
||
389 pollv
[2].revents
& POLLIN
)
391 if (pollv
[0].revents
& POLLIN
) {
392 nx
=read(STDIN_FILENO
,bufin
,sizeof(bufin
));
393 /* if POLLIN but not data it means that the stream has been
394 * closed at the other end */
395 /*fprintf(stderr,"%s: RECV %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/
398 vdestream_recv(vdestream
, bufin
, nx
);
400 if (pollv
[1].revents
& POLLIN
) {
401 nx
=vde_recv(conn
,bufin
,BUFSIZE
-2,0);
403 perror("vde_plug: recvfrom ");
406 vdestream_send(vdestream
, bufin
, nx
);
407 /*fprintf(stderr,"%s: SENT %d %x %x \n",myname,nx,bufin[0],bufin[1]);*/