1 /* Copyright 2005 Renzo Davoli - VDE-2
2 * --pidfile/-p and cleanup management by Mattia Belletti (C) 2004.
3 * Licensed under the GPLv2
4 * Modified by Ludovico Gardenghi 2005
5 * -g option (group management) by Daniel P. Berrange
6 * dir permission patch by Alessio Caprari 2006
19 #include <sys/types.h>
21 #include <sys/ioctl.h>
22 #include <sys/socket.h>
23 #include <sys/types.h>
31 //#include <linux/if_tun.h>
36 #include <sockutils.h>
39 static struct swmodule swmi
;
40 static struct mod_support modfun
;
41 static unsigned int ctl_type
;
42 static unsigned int wd_type
;
43 static unsigned int data_type
;
44 static int mode
= 0700;
46 static char *ctl_socket
;
47 static gid_t grp_owner
= -1;
49 #define MODULENAME "unix prog"
51 #define DATA_BUF_SIZE 131072
52 #define SWITCH_MAGIC 0xfeedface
55 enum request_type
{ REQ_NEW_CONTROL
, REQ_NEW_PORT0
};
59 enum request_type type
;
62 unsigned char addr
[ETH_ALEN
];
63 struct sockaddr_un name
;
72 enum request_type type
;
73 struct sockaddr_un sock
;
82 static int send_datasock(int fd
, int ctl_fd
, void *packet
, int len
, void *data
, int port
)
85 struct sockaddr
*dst
=(struct sockaddr
*)data
;
87 n
= len
- sendto(fd
, packet
, len
, 0, dst
, sizeof(struct sockaddr_un
));
91 if(errno
!= EAGAIN
) printlog(LOG_WARNING
,"send_sockaddr port %d: %s",port
,strerror(errno
));
101 static void closeport(int fd
, int portno
)
107 static int newport(int fd
, int portno
)
110 struct sockaddr_un sun
;
112 int sockbufsize
= DATA_BUF_SIZE
;
113 int optsize
= sizeof(sockbufsize
);
116 if((data_fd
= socket(PF_UNIX
, SOCK_DGRAM
, 0)) < 0){
117 printlog(LOG_ERR
,"socket: %s",strerror(errno
));
120 if(fcntl(data_fd
, F_SETFL
, O_NONBLOCK
) < 0){
121 printlog(LOG_ERR
,"Setting O_NONBLOCK on data fd %s",strerror(errno
));
126 if(setsockopt(data_fd
, SOL_SOCKET
, SO_SNDBUF
, &sockbufsize
, optsize
) < 0)
127 printlog(LOG_WARNING
, "Warning: setting send buffer size on data fd %d to %d failed, expect packet loss: %s",
128 data_fd
, sockbufsize
, strerror(errno
));
129 if(setsockopt(data_fd
, SOL_SOCKET
, SO_RCVBUF
, &sockbufsize
, optsize
) < 0)
130 printlog(LOG_WARNING
, "Warning: setting send buffer size on data fd %d to %d failed, expect packet loss: %s",
131 data_fd
, sockbufsize
, strerror(errno
));
134 sun
.sun_family
= AF_UNIX
;
135 snprintf(sun
.sun_path
,sizeof(sun
.sun_path
),"%s/%03d",ctl_socket
,portno
);
136 if ((unlink(sun
.sun_path
) < 0 && errno
!= ENOENT
) ||
137 bind(data_fd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
138 printlog(LOG_ERR
,"Binding to data socket %s",strerror(errno
));
139 close_ep(portno
-1,fd
);
142 chmod(sun
.sun_path
,mode
);
143 if(chown(sun
.sun_path
,-1,grp_owner
) < 0) {
144 printlog(LOG_ERR
, "chown: %s", strerror(errno
));
145 close_ep(portno
-1,fd
);
149 add_fd(data_fd
,data_type
,portno
);
154 static void *memdup(void *src
,int size
)
156 void *dst
=malloc(size
);
158 memcpy(dst
,src
,size
);
162 #define GETFILEOWNER(PATH) ({\
164 (stat((PATH),&s)?-1:s.st_uid); \
167 static int checksockperm(char *path
,char *lpath
)
170 if (access(path
,R_OK
| W_OK
) != 0)
172 if (geteuid() == 0) { /* switch run by root */
174 if ((rvuid
=GETFILEOWNER(path
)) < 0)
176 luid
=GETFILEOWNER(lpath
);
177 if (luid
> 0 && luid
!= rvuid
) {
185 static int new_port_v1_v3(int fd
, int type_port
,
186 struct sockaddr_un
*sun_out
)
189 enum request_type type
= type_port
& 0xff;
190 int port_request
=type_port
>> 8;
192 struct sockaddr_un sun_in
;
196 /* no break: falltrough */
197 case REQ_NEW_CONTROL
:
198 port
= setup_ep(port_request
, fd
, memdup(sun_out
,sizeof(struct sockaddr_un
)), &modfun
);
203 sun_in
.sun_family
= AF_UNIX
;
204 snprintf(sun_in
.sun_path
,sizeof(sun_in
.sun_path
),"%s/%03d",ctl_socket
,port
);
205 if (sun_out
->sun_path
[0] != 0) { //not for unnamed sockets
206 if ((cluid
=checksockperm(sun_out
->sun_path
,sun_in
.sun_path
)) < 0) {
207 printlog(LOG_WARNING
,"Data_out socket permission: %s",strerror(errno
));
212 n
= write(fd
, &sun_in
, sizeof(sun_in
));
213 if(n
!= sizeof(sun_in
)){
214 printlog(LOG_WARNING
,"Sending data socket name %s",strerror(errno
));
218 if (type
==REQ_NEW_PORT0
)
219 setmgmtperm(sun_in
.sun_path
);
220 else if (cluid
> 0) {
221 chown(sun_in
.sun_path
,cluid
,-1);
222 chmod(sun_in
.sun_path
,mode
& 0700);
227 printlog(LOG_WARNING
,"Bad request type : %d", type
);
233 static void handle_input(unsigned char type
,int fd
,int revents
,int *arg
)
235 if (type
== data_type
) {
236 struct bipacket packet
;
237 struct sockaddr sock
;
239 socklen_t socklen
= sizeof(sock
);
241 len
=recvfrom(fd
, &(packet
.p
), sizeof(struct packet
),0, &sock
, &socklen
);
243 if (errno
== EAGAIN
) return;
244 printlog(LOG_WARNING
,"Reading data: %s",strerror(errno
));
247 printlog(LOG_WARNING
,"EOF data port: %s",strerror(errno
));
248 else if(len
>= ETH_HEADER_SIZE
)
249 handle_in_packet(*arg
, &(packet
.p
), len
);
251 else if (type
== wd_type
) {
252 char reqbuf
[REQBUFLEN
+1];
253 union request
*req
=(union request
*)reqbuf
;
256 len
= read(fd
, reqbuf
, REQBUFLEN
);
259 printlog(LOG_WARNING
,"Reading request %s", strerror(errno
));
263 } else if (len
> 0) {
265 if(req
->v1
.magic
== SWITCH_MAGIC
){
267 if(req
->v3
.version
== 3) {
268 port
=new_port_v1_v3(fd
, req
->v3
.type
, &(req
->v3
.sock
));
271 setup_description(*arg
,fd
,strdup(req
->v3
.description
));
274 else if(req
->v3
.version
> 2 || req
->v3
.version
== 2) {
275 printlog(LOG_ERR
, "Request for a version %d port, which this "
276 "vde_switch doesn't support", req
->v3
.version
);
280 *arg
=port
=new_port_v1_v3(fd
, req
->v1
.type
, &(req
->v1
.u
.new_control
.name
));
281 setup_description(*arg
,fd
,strdup(req
->v1
.description
));
285 printlog(LOG_WARNING
,"V0 request not supported");
293 else /*if (type == ctl_type)*/ {
294 struct sockaddr addr
;
299 new = accept(fd
, &addr
, &len
);
301 printlog(LOG_WARNING
,"accept %s",strerror(errno
));
304 if(fcntl(new, F_SETFL
, O_NONBLOCK
) < 0){
305 printlog(LOG_WARNING
,"fcntl - setting O_NONBLOCK %s",strerror(errno
));
310 add_fd(new,wd_type
,-1);
314 static void cleanup(unsigned char type
,int fd
,int arg
)
316 struct sockaddr_un clun
;
318 snprintf(clun
.sun_path
,sizeof(clun
.sun_path
),"%s/ctl",ctl_socket
);
319 if(unlink(clun
.sun_path
) < 0)
320 printlog(LOG_WARNING
,"Couldn't remove ctl socket '%s' : %s", ctl_socket
, strerror(errno
));
321 else if(rmdir(ctl_socket
) < 0)
322 printlog(LOG_WARNING
,"Couldn't remove ctl dir '%s' : %s", ctl_socket
, strerror(errno
));
324 if (type
== data_type
&& arg
>=0) {
325 snprintf(clun
.sun_path
,sizeof(clun
.sun_path
),"%s/%03d",ctl_socket
,arg
);
326 unlink(clun
.sun_path
);
332 static struct option long_options
[] = {
334 {"vdesock", 1, 0, 's'},
337 {"group", 1, 0, 'g'},
340 #define Nlong_options (sizeof(long_options)/sizeof(struct option));
342 static void usage(void)
345 "(opts from datasock module)\n"
346 " -s, --sock SOCK control directory pathname\n"
347 " -s, --vdesock SOCK Same as --sock SOCK\n"
348 " -s, --unix SOCK Same as --sock SOCK\n"
349 " -m, --mod MODE Standard access mode for comm sockets (octal)\n"
350 " -g, --group GROUP Group owner for comm sockets\n"
354 static int parseopt(int c
, char *optarg
)
360 ctl_socket
=strdup(optarg
);
363 sscanf(optarg
,"%o",&mode
);
366 if (!(grp
= getgrnam(optarg
))) {
367 fprintf(stderr
, "No such group '%s'\n", optarg
);
370 grp_owner
=grp
->gr_gid
;
378 static void init(void)
381 struct sockaddr_un sun
;
384 if((connect_fd
= socket(PF_UNIX
, SOCK_STREAM
, 0)) < 0){
385 printlog(LOG_ERR
,"socket: %s",strerror(errno
));
388 if(setsockopt(connect_fd
, SOL_SOCKET
, SO_REUSEADDR
, (char *) &one
,
390 printlog(LOG_ERR
,"setsockopt: %s",strerror(errno
));
393 if(fcntl(connect_fd
, F_SETFL
, O_NONBLOCK
) < 0){
394 printlog(LOG_ERR
,"Setting O_NONBLOCK on connection fd: %s",strerror(errno
));
397 if (mkdir(ctl_socket
, (mode
& 0700 ? 0700 : 0) |
398 (mode
& 0070 ? 0050 : 0) | (mode
& 0007 ? 0005 : 0)) < 0) {
399 printlog(LOG_ERR
,"creating vde ctl dir: %s",strerror(errno
));
402 sun
.sun_family
= AF_UNIX
;
403 snprintf(sun
.sun_path
,sizeof(sun
.sun_path
),"%s/ctl",ctl_socket
);
404 if(bind(connect_fd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
405 if((errno
== EADDRINUSE
) && still_used(&sun
)) return;
406 else if(bind(connect_fd
, (struct sockaddr
*) &sun
, sizeof(sun
)) < 0){
407 printlog(LOG_ERR
,"bind %s",strerror(errno
));
411 chmod(sun
.sun_path
,mode
);
412 if(chown(sun
.sun_path
,-1,grp_owner
) < 0) {
413 printlog(LOG_ERR
, "chown: %s", strerror(errno
));
416 if(listen(connect_fd
, 15) < 0){
417 printlog(LOG_ERR
,"listen: %s",strerror(errno
));
420 ctl_type
=add_type(&swmi
,0);
421 wd_type
=add_type(&swmi
,0);
422 data_type
=add_type(&swmi
,1);
423 add_fd(connect_fd
,ctl_type
,-1);
426 static int showinfo(int fd
)
428 printoutc(fd
,"ctl dir %s",ctl_socket
);
429 printoutc(fd
,"std mode 0%03o",mode
);
433 static struct comlist cl
[]={
434 {"ds","============","DATA SOCKET MENU",NULL
,NOARG
},
435 {"ds/showinfo","","show ds info",showinfo
,NOARG
|WITHFD
},
438 static void delep (int fd
, void* data
, void *descr
)
440 if (fd
>=0) remove_fd(fd
);
441 if (data
) free(data
);
442 if (descr
) free(descr
);
445 void start_datasock(void)
447 ctl_socket
= (geteuid()==0)?VDESTDSOCK
:VDETMPSOCK
;
448 modfun
.modname
=swmi
.swmname
=MODULENAME
;
449 swmi
.swmnopts
=Nlong_options
;
450 swmi
.swmopts
=long_options
;
452 swmi
.parseopt
=parseopt
;
454 swmi
.handle_input
=handle_input
;
455 swmi
.cleanup
=cleanup
;
456 modfun
.sender
=send_datasock
;
457 modfun
.newport
=newport
;
459 modfun
.delport
=closeport
;