1 /* Copyright 2003 Renzo Davoli
2 * Licensed under the GPL
13 #include <sys/ioctl.h>
14 #include <sys/socket.h>
18 #include <sys/utsname.h>
25 #include <sys/types.h>
28 #include <arpa/inet.h>
31 #define SWITCH_MAGIC 0xfeedface
35 enum request_type
{ REQ_NEW_CONTROL
};
40 enum request_type type
;
41 struct sockaddr_un sock
;
45 #define myname me.nodename
48 static struct passwd
*callerpwd
;
49 static char host
[256];
51 void write_syslog_entry(char *message
)
56 openlog("vde_plug", 0, LOG_USER
);
59 callerpwd
=getpwuid(getuid());
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");
89 unsigned char dest
[ETH_ALEN
];
90 unsigned char src
[ETH_ALEN
];
91 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];
109 unsigned char ip4list
[MAX_IP
][4];
110 unsigned char ip6list
[MAX_IP
][16];
111 static unsigned char nulladdr
[16];
113 static int hash4(char *addr
)
115 return((addr
[0]+2*addr
[1]+3*addr
[2]+5*addr
[3]) % MAX_IP
);
118 static int hash6(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
[7]+23*addr
[8]+29*addr
[9]+31*addr
[10]+
123 37*addr
[7]+41*addr
[8]+43*addr
[9]+47*addr
[10]) % MAX_IP
);
126 static void vde_ip_check(const char *buf
,int rnx
)
128 struct packet
*p
=(struct packet
*) buf
;
132 if (p
->header
.proto
[0]==0x08 && p
->header
.proto
[1]==0x00 &&
133 p
->body
.v4
.version
== 0x45) {
135 i
=hash4(p
->body
.v4
.ip4src
);
136 j
=(i
+MAX_IP
-1)%MAX_IP
;
138 /* more frequent case first */
139 if (memcmp(p
->body
.v4
.ip4src
,ip4list
[i
],4) == 0)
141 else if (memcmp(ip4list
[i
],nulladdr
,4) == 0) {
142 memcpy(ip4list
[i
],p
->body
.v4
.ip4src
,4);
143 syslog(LOG_INFO
,"user %s Real-IP %s has got VDE-IP4 %s",callerpwd
->pw_name
,host
,inet_ntop(AF_INET
,ip4list
[i
],addr
,256));
147 syslog(LOG_ERR
,"IPv4 table full. Exiting\n");
154 else if (p
->header
.proto
[0]==0x86 && p
->header
.proto
[1]==0xdd &&
155 p
->body
.v4
.version
== 0x60) {
157 i
=hash6(p
->body
.v6
.ip6src
);
158 j
=(i
+MAX_IP
-1)%MAX_IP
;
160 /* more frequent case first */
161 if (memcmp(p
->body
.v6
.ip6src
,ip6list
[i
],16) == 0)
163 else if (memcmp(ip6list
[i
],nulladdr
,16) == 0) {
164 memcpy(ip6list
[i
],p
->body
.v6
.ip6src
,16);
165 syslog(LOG_INFO
,"user %s Real-IP %s has got VDE-IP6 %s",callerpwd
->pw_name
,host
,inet_ntop(AF_INET6
,ip6list
[i
],addr
,256));
169 syslog(LOG_ERR
,"IPv6 table full. Exiting\n");
180 static int send_fd(char *name
, int fddata
, struct sockaddr_un
*datasock
, int group
)
183 struct request_v3 req
;
186 struct sockaddr_un sock
;
188 if((fdctl
= socket(AF_UNIX
, SOCK_STREAM
, 0)) < 0){
193 sock
.sun_family
= AF_UNIX
;
194 snprintf(sock
.sun_path
, sizeof(sock
.sun_path
), "%s", name
);
195 if(connect(fdctl
, (struct sockaddr
*) &sock
, sizeof(sock
))){
200 req
.magic
=SWITCH_MAGIC
;
202 req
.type
=REQ_NEW_CONTROL
+((group
> 0)?((geteuid()<<8) + group
) << 8:0);
204 req
.sock
.sun_family
=AF_UNIX
;
205 memset(req
.sock
.sun_path
, 0, sizeof(req
.sock
.sun_path
));
206 sprintf(&req
.sock
.sun_path
[1], "%5d", pid
);
208 if(bind(fddata
, (struct sockaddr
*) &req
.sock
, sizeof(req
.sock
)) < 0){
213 if (send(fdctl
,&req
,sizeof(req
),0) < 0) {
218 if (recv(fdctl
,datasock
,sizeof(struct sockaddr_un
),0)<0) {
226 unsigned char bufin
[BUFSIZE
];
227 #define MIN(X,Y) ((X)<(Y))?(X):(Y)
229 void splitpacket(const unsigned char *buf
,int size
,int fd
, struct sockaddr_un
*pd
)
231 static unsigned char fragment
[BUFSIZE
];
233 static unsigned int rnx
,remaining
;
235 //fprintf(stderr,"%s: splitpacket rnx=%d remaining=%d size=%d\n",myname,rnx,remaining,size);
238 register int amount
=MIN(remaining
,size
);
239 //fprintf(stderr,"%s: fragment amount %d\n",myname,amount);
240 memcpy(fragp
,buf
,amount
);
246 //fprintf(stderr,"%s: delivered defrag %d\n",myname,rnx);
247 //send(fd,fragment,rnx,0);
248 sendto(fd
,fragment
,rnx
,0,(struct sockaddr
*) pd
,sizeof(struct sockaddr_un
));
254 rnx
=(buf
[0]<<8)+buf
[1];
256 //fprintf(stderr,"%s: packet %d size %d %x %x\n",myname,rnx,size,buf[0],buf[1]);
259 fprintf(stderr
,"%s: Packet length error size %d rnx %d\n",myname
,size
,rnx
);
264 //fprintf(stderr,"%s: begin defrag %d\n",myname,rnx);
266 memcpy(fragp
,buf
,size
);
271 //fprintf(stderr,"%s: deliver %d\n",myname,rnx);
272 //send(fd,buf,rnx,0);
275 vde_ip_check(buf
,rnx
);
277 sendto(fd
,buf
,rnx
,0,(struct sockaddr
*) pd
,sizeof(struct sockaddr_un
));
285 struct pollfd pollv
[]={{STDIN_FILENO
,POLLIN
|POLLHUP
,0},{0,POLLIN
|POLLHUP
,0}};
287 static void netusage() {
289 write_syslog_entry("FAILED");
291 fprintf (stderr
,"This is a Virtual Distributed Ethernet (vde) tunnel broker. \n"
292 "This is not a login shell, only vde_plug can be executed\n");
296 static void usage(char *progname
) {
297 fprintf (stderr
,"Usage: %s [-g num] [socketname]\n ( 0 < num < 256 )\n\n",progname
);
301 int main(int argc
, char **argv
)
305 struct sockaddr_un dataout
;
306 struct sockaddr_un datain
;
314 if (argv
[0][0] == '-')
315 netusage(); //implies exit
321 int option_index
= 0;
323 static struct option long_options
[] = {
324 {"group", 1, 0, 's'},
326 {"vdesock", 1, 0, 's'},
331 c
= getopt_long_only (argc
, argv
, "c:g:s:l",
332 long_options
, &option_index
);
338 if (strcmp(optarg
,"vde_plug")==0) {
340 write_syslog_entry("START");
341 atexit(write_syslog_close
);
349 netusage(); //implies exit
354 if (group
<= 0 || group
> 255 )
355 usage(argv
[0]); //implies exit
359 usage(argv
[0]); //implies exit
363 sockname
=strdup(optarg
);
368 write_syslog_entry("START");
369 atexit(write_syslog_close
);
375 usage(argv
[0]); //implies exit
379 if (optind
< argc
&& sockname
==VDESTDSOCK
)
380 sockname
=argv
[optind
];
382 if((fddata
= socket(AF_UNIX
, SOCK_DGRAM
, 0)) < 0){
386 connected_fd
=send_fd(sockname
, fddata
, &dataout
, group
);
390 result
=poll(pollv
,2,-1);
391 if (pollv
[0].revents
& POLLHUP
|| pollv
[1].revents
& POLLHUP
)
393 if (pollv
[0].revents
& POLLIN
) {
394 nx
=read(STDIN_FILENO
,bufin
,sizeof(bufin
));
395 /* if POLLIN but not data it means that the stream has been
396 * closed at the other end */
399 splitpacket(bufin
,nx
,fddata
,&dataout
);
400 //sendto(fddata,bufin,nx,0,(struct sockaddr *) &dataout,sizeof(dataout));
403 if (pollv
[1].revents
& POLLIN
) {
404 datainsize
=sizeof(datain
);
405 nx
=recvfrom(fddata
,bufin
+2,BUFSIZE
-2,0,(struct sockaddr
*) &datain
, &datainsize
);
407 perror("vde_plug: recvfrom ");
412 write(STDOUT_FILENO
,bufin
,nx
+2);
413 //fprintf(stderr,"%s: SENT %d %x %x \n",myname,nx,bufin[0],bufin[1]);