Several BugFixes (see bug-reports from "accounts")
[vde.git] / vde-2 / src / vde_switch / plugins / iplog.c
blob3bb113c84c2675cbb09fa7f530b73a647dc3ae95
1 /* This is part of VDE Virtual Distributed Internet
3 * iplog: ip logging plugin for vde_switch
4 *
5 * Copyright 2010 Renzo Davoli University of Bologna - Italy
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License, version 2, as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
22 #define _GNU_SOURCE
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <fcntl.h>
27 #include <stdint.h>
29 #include <config.h>
30 #include <vde.h>
31 #include <syslog.h>
32 #include <errno.h>
33 #include <limits.h>
34 #include <unistd.h>
35 #include <sys/types.h>
36 #include <sys/socket.h>
37 #include <netdb.h>
38 #include <stdio.h>
39 #include <string.h>
40 #include <netinet/in.h>
41 #include <sys/uio.h>
42 #include <pwd.h>
43 #include <ctype.h>
45 #include <vdecommon.h>
47 #include <vdeplugin.h>
49 static char *logfile;
50 static int logfilefd=-1;
52 #define D_LOGIP 0300
53 static struct dbgcl dl[]= {
54 {"iplog/newip","show new ip addresses",D_LOGIP|D_PLUS},
56 #define D_LOGIP_NEWIP (dl)
58 /* lists of ip ranges to log */
59 struct ip4logaddr {
60 struct ip4logaddr *next;
61 uint32_t addr;
62 uint32_t mask;
65 struct ip6logaddr {
66 struct ip6logaddr *next;
67 uint32_t addr[4];
68 uint32_t mask[4];
71 struct ip4logaddr *ip4loghead;
72 struct ip6logaddr *ip6loghead;
74 /* packet header structure layer 2 and 3*/
75 #define ETH_ALEN 6
76 struct header {
77 unsigned char dest[ETH_ALEN];
78 unsigned char src[ETH_ALEN];
79 unsigned char proto[2];
82 union body {
83 struct {
84 unsigned char version;
85 unsigned char filler[11];
86 unsigned char ip4src[4];
87 unsigned char ip4dst[4];
88 } v4;
89 struct {
90 unsigned char version;
91 unsigned char filler[7];
92 unsigned char ip6src[16];
93 unsigned char ip6dst[16];
94 } v6;
95 struct {
96 unsigned char priovlan[2];
97 } vlan;
100 /* vde plugin data */
101 struct plugin vde_plugin_data={
102 .name="iplog",
103 .help="log ip/port/user assignment",
106 /* translate ipv4 ipv6 addresses into strings for logging */
107 static inline int ip42string(uint32_t *addr, char *hostname, unsigned int len)
109 struct sockaddr_in ip4addr;
110 ip4addr.sin_family=AF_INET;
111 ip4addr.sin_port=0;
112 ip4addr.sin_addr.s_addr = *addr;
113 return getnameinfo((struct sockaddr *)&ip4addr,sizeof(ip4addr),
114 hostname,len,NULL,0,NI_NUMERICHOST);
117 static inline int ip62string(uint32_t *addr, char *hostname, unsigned int len)
119 struct sockaddr_in6 ip6addr;
120 ip6addr.sin6_family=AF_INET6;
121 ip6addr.sin6_port=0;
122 ip6addr.sin6_flowinfo=0;
123 ip6addr.sin6_scope_id=0;
124 memcpy(&ip6addr.sin6_addr.s6_addr,addr,16);
125 return getnameinfo((struct sockaddr *)&ip6addr,sizeof(ip6addr),
126 hostname,len,NULL,0,NI_NUMERICHOST);
129 /* hash table of recently seen ip addresses, collision lists are double linked */
130 #define IP_HASH_SIZE 1024
132 struct ip_hash_entry {
133 struct ip_hash_entry *next;
134 struct ip_hash_entry **prev;
135 time_t last_seen;
136 int port;
137 short vlan;
138 unsigned char srcmac[ETH_ALEN];
139 short len;
140 unsigned char ipaddr[4];
143 static struct ip_hash_entry **iph;
145 static inline int ip_hash(int len,unsigned char *addr)
147 if (len == 4)
148 return((addr[0]+2*addr[1]+3*addr[2]+5*addr[3]) % IP_HASH_SIZE);
149 else
150 return((addr[0]+2*addr[1]+3*addr[2]+5*addr[3]+
151 7*addr[4]+11*addr[5]+13*addr[6]+17*addr[7]+
152 19*addr[8]+23*addr[9]+29*addr[10]+31*addr[11]+
153 37*addr[12]+41*addr[13]+43*addr[14]+47*addr[15]) % IP_HASH_SIZE);
156 /* search ip address into the hash tacle and add it if it does not exist.
157 log each new item added */
158 static void ip_find_in_hash_update(int len, unsigned char *addr, unsigned char *srcmac, int vlan, int port)
160 struct ip_hash_entry *e;
161 int k = ip_hash(len, addr);
162 time_t now;
163 for(e = iph[k]; e && memcmp(e->ipaddr, addr, len) && e->len == len &&
164 e->vlan == vlan; e = e->next)
166 if(e == NULL) {
167 e = (struct ip_hash_entry *) malloc(sizeof(*e)+(len-4));
168 if(e == NULL){
169 printlog(LOG_WARNING,"Failed to malloc ip_hash entry %s",strerror(errno));
170 return;
172 memcpy(e->ipaddr, addr, len);
173 if(iph[k] != NULL) iph[k]->prev = &(e->next);
174 e->next = iph[k];
175 e->prev = &(iph[k]);
176 e->vlan = vlan;
177 e->len = len;
178 e->port = -1;
179 iph[k] = e;
181 now=qtime();
182 e->last_seen = now;
183 if(e->port != port || e->vlan != vlan || memcmp(e->srcmac,srcmac,ETH_ALEN)!=0) {
184 e->port=port;
185 e->vlan = vlan;
186 memcpy(e->srcmac,srcmac,ETH_ALEN);
187 char hostname[100];
188 char msg[1024];
189 char lf[]="\n";
190 char stime[26];
191 struct iovec iov[]={{stime+4,16},{msg,0},{lf,1}};
193 if ((len==4 && ip42string((uint32_t *)addr,hostname,sizeof(hostname))==0) ||
194 (len==16 && ip62string((uint32_t *)addr,hostname,sizeof(hostname))==0)) {
195 struct passwd *pwd;
196 char *username;
197 int epn;
198 char *descr;
199 if ((pwd=getpwuid(port_user(port))) == NULL)
200 username="(none)";
201 else
202 username=pwd->pw_name;
203 iov[1].iov_len=snprintf(msg,sizeof(msg),"ipv%d %s mac=%02x:%02x:%02x:%02x:%02x:%02x port=%d vlan=%d user=%s",
204 (len==4)?4:6, hostname,
205 srcmac[0], srcmac[1], srcmac[2], srcmac[3], srcmac[4], srcmac[5],
206 port, vlan, username);
207 for (epn=0; (descr=port_descr(port,epn)) != NULL; epn++) {
208 int len=iov[1].iov_len;
209 int descrlen=snprintf(msg+len,sizeof(msg)-len," \"%s\"",descr);
210 iov[1].iov_len+=descrlen;
212 if (logfilefd >= 0) {
213 time_t ntime=time(&ntime);
214 ctime_r(&ntime,stime);
215 writev(logfilefd,iov,3);
216 } else if (logfilefd != -1)
217 syslog(LOG_INFO, "%s", msg);
218 DBGOUT(D_LOGIP_NEWIP,"%s",msg);
223 /* pass through the hash table and execute function f for each element */
224 static void ip_for_all_hash(void (*f)(struct ip_hash_entry *, void *), void *arg)
226 int i;
227 struct ip_hash_entry *e, *next;
229 for(i = 0; i < IP_HASH_SIZE; i++){
230 for(e = iph[i]; e; e = next){
231 next = e->next;
232 (*f)(e, arg);
237 /* delete a hash table entry */
238 static inline void delete_hash_entry(struct ip_hash_entry *old)
240 *((old)->prev)=(old)->next;
241 if((old)->next != NULL) (old)->next->prev = (old)->prev;
242 free((old));
246 #define IP_GC_INTERVAL 10
247 #define IP_GC_EXPIRE 360
248 static int ip_gc_interval=IP_GC_INTERVAL;
249 static int ip_gc_expire=IP_GC_EXPIRE;
250 static unsigned int ip_gc_timerno;
252 /* clean from the hash table entries older than IP_GC_EXPIRE seconds, given that
253 * 'now' points to a time_t structure describing the current time */
254 static void ip_gc(struct ip_hash_entry *e, void *expiretime)
256 if(e->last_seen <= *((time_t *)expiretime))
257 delete_hash_entry(e);
260 /* clean old entries in the hash table 'h', and prepare the timer to be called
261 * again between GC_INTERVAL seconds */
262 static void ip_hash_gc(void *arg)
264 time_t t = qtime() - ip_gc_expire;
265 ip_for_all_hash(ip_gc, &t);
268 /* upcall from vde: new incomping packet */
269 #define UINT32(X) (((uint32_t *)&(X)))
270 static int iplog_pktin(struct dbgcl *event,void *arg,va_list v)
272 int vlan=0;
273 int port=va_arg(v,int);
274 unsigned char *buf=va_arg(v,unsigned char *);
275 //int len=va_arg(v,int);
276 struct header *ph=(struct header *) buf;
277 union body *pb=(union body *)(ph+1);
278 //fprintf(stderr,"packet from port %d len %d\n",port,len);
279 if (ph->proto[0]==0x81 && ph->proto[1]==0x00) { /*VLAN*/
280 vlan=((pb->vlan.priovlan[0] << 8) + pb->vlan.priovlan[1]) & 0xfff;
281 ph=(struct header *)(((char *)ph)+4);
282 pb=(union body *)(((char *)pb)+4);
284 if (ph->proto[0]==0x08 && ph->proto[1]==0x00 &&
285 pb->v4.version == 0x45) {
286 /*v4 */
287 struct ip4logaddr *ip4scan;
288 /* is the packet in one of the logged ranges? */
289 for (ip4scan=ip4loghead; ip4scan!=NULL; ip4scan=ip4scan->next) {
290 /*printf("%x %x %x\n",UINT32(pb->v4.ip4src[0]) , ip4scan->mask ,
291 ip4scan->addr);*/
292 uint32_t *addr=UINT32(pb->v4.ip4src[0]);
293 if ((addr[0] & ip4scan->mask) ==
294 ip4scan->addr) {
295 ip_find_in_hash_update(4,pb->v4.ip4src,ph->src,vlan,port);
296 break;
300 else if (ph->proto[0]==0x86 && ph->proto[1]==0xdd &&
301 pb->v4.version == 0x60) {
302 /*v6 */
303 struct ip6logaddr *ip6scan;
304 /* is the packet in one of the logged ranges? */
305 for (ip6scan=ip6loghead; ip6scan!=NULL; ip6scan=ip6scan->next) {
306 /*printf("%x %x %x:",UINT32(pb->v6.ip6src[0]) , ip6scan->mask[0] , ip6scan->addr[0]);
307 printf("%x %x %x:",UINT32(pb->v6.ip6src[4]) , ip6scan->mask[1] , ip6scan->addr[1]);
308 printf("%x %x %x:",UINT32(pb->v6.ip6src[8]) , ip6scan->mask[2] , ip6scan->addr[2]);
309 printf("%x %x %x:",UINT32(pb->v6.ip6src[12]) , ip6scan->mask[3] , ip6scan->addr[3]);
310 printf("\n");*/
311 uint32_t *addr=UINT32(pb->v6.ip6src[0]);
312 if (
313 ((addr[0] & ip6scan->mask[0]) == ip6scan->addr[0]) &&
314 ((addr[1] & ip6scan->mask[1]) == ip6scan->addr[1]) &&
315 ((addr[2] & ip6scan->mask[2]) == ip6scan->addr[2]) &&
316 ((addr[3] & ip6scan->mask[3]) == ip6scan->addr[3])
319 ip_find_in_hash_update(16,pb->v6.ip6src,ph->src,vlan,port);
320 break;
324 return 0;
327 /* delete all ip address on a specific port (when the port is closed) */
328 static void port_gc(struct ip_hash_entry *e, void *arg)
330 int *port=arg;
331 if(*port == e->port)
332 delete_hash_entry(e);
335 /* upcall from vde: a port has been closed */
336 static int iplog_port_minus(struct dbgcl *event,void *arg,va_list v)
338 int port=va_arg(v,int);
339 ip_for_all_hash(&port_gc, &port);
340 return 0;
343 /*user interface: showinfo */
344 static int ipshowinfo(FILE *fd)
346 printoutc(fd,"iplog: ip/port/user logging plugin");
347 if (logfilefd<0) {
348 if (logfilefd == -1)
349 printoutc(fd,"log disabled");
350 else
351 printoutc(fd,"log on syslog");
352 } else
353 printoutc(fd,"log on file %s",logfile);
354 printoutc(fd,"GC interval %d secs",ip_gc_interval);
355 printoutc(fd,"GC expire %d secs",ip_gc_expire);
356 return 0;
359 /* close the old log file */
360 static void closelogfile(void)
362 if (logfilefd >= 0)
363 close(logfilefd);
364 if (logfile != NULL)
365 free(logfile);
368 /* change the log file */
369 static int iplogfile(char *arg)
371 if (*arg) {
372 if (strcmp(arg,"-")==0) {
373 closelogfile();
374 logfilefd=-2;
375 return 0;
376 } else {
377 int fd;
378 fd=open(arg,O_CREAT|O_WRONLY|O_APPEND,0600);
379 if (fd>=0) {
380 char abspath[PATH_MAX];
381 closelogfile();
382 logfilefd=fd;
383 vde_realpath(arg,abspath);
384 logfile=strdup(abspath);
385 return 0;
386 } else
387 return ENOENT;
389 } else {
390 closelogfile();
391 logfilefd=-1;
392 return 0;
396 /* add a v4 range (recursive) */
397 static int iplog4radd(struct ip4logaddr **ph, uint32_t addr, uint32_t mask)
399 if (*ph == NULL) {
400 *ph=malloc(sizeof(struct ip4logaddr));
401 if (*ph==NULL)
402 return ENOMEM;
403 else {
404 (*ph)->next=NULL;
405 (*ph)->addr=addr;
406 (*ph)->mask=mask;
407 return 0;
409 } else {
410 if ((*ph)->addr==addr && (*ph)->mask==mask)
411 return EEXIST;
412 else
413 return iplog4radd(&((*ph)->next),addr,mask);
417 /* add a v6 range (recursive) */
418 static int iplog6radd(struct ip6logaddr **ph, uint32_t addr[4], uint32_t mask[4])
420 if (*ph == NULL) {
421 *ph=malloc(sizeof(struct ip6logaddr));
422 if (*ph==NULL)
423 return ENOMEM;
424 else {
425 (*ph)->next=NULL;
426 memcpy((void *)((*ph)->addr),addr,16);
427 memcpy((void *)((*ph)->mask),mask,16);
428 return 0;
430 } else {
431 if (memcmp(&((*ph)->addr),addr,16) == 0 &&
432 memcmp(&((*ph)->mask),mask,16) == 0)
433 return EEXIST;
434 else
435 return iplog6radd(&((*ph)->next),addr,mask);
439 /* delete a v4 range (recursive) */
440 static int iplog4rdel(struct ip4logaddr **ph, uint32_t addr, uint32_t mask)
442 if (*ph == NULL) {
443 return ENOENT;
444 } else {
445 if ((*ph)->addr==addr && (*ph)->mask==mask) {
446 struct ip4logaddr *this=*ph;
447 *ph=(*ph)->next;
448 free(this);
449 return 0;
450 } else
451 return iplog4rdel(&((*ph)->next),addr,mask);
455 /* delete a v6 range (recursive) */
456 static int iplog6rdel(struct ip6logaddr **ph, uint32_t addr[4], uint32_t mask[4])
458 if (*ph == NULL) {
459 return ENOENT;
460 } else {
461 if (memcmp(&((*ph)->addr),addr,16) == 0 &&
462 memcmp(&((*ph)->mask),mask,16) == 0) {
463 struct ip6logaddr *this=*ph;
464 *ph=(*ph)->next;
465 free(this);
466 return 0;
467 } else
468 return iplog6rdel(&((*ph)->next),addr,mask);
472 /* create a mask from the number of bits */
473 static void n2mask(int len,int n, uint32_t *out)
475 char m[len];
476 int i;
477 for (i=0;i<len;i++,n-=8) {
478 if (n>=8)
479 m[i]=0xff;
480 else if (n>0)
481 m[i]=~((1<<(8-n))-1);
482 else
483 m[i]=0;
485 len=(len+sizeof(uint32_t)-1)/sizeof(uint32_t);
486 for (i=0;i<len;i++)
487 out[i]=*(((uint32_t *)m)+i);
490 /* compute the number of bits from a mask */
491 static int mask2n(int len, void *addr)
493 char *m=addr;
494 int n=0;
495 int i,sm;
496 for (i=0;i<len;i++) {
497 for (sm=0x80;sm!=0;sm>>=1) {
498 if (m[i] & sm)
499 n++;
500 else
501 return n;
504 return n;
507 /* convert an ipv4 or ipv6 address into addr/mask */
508 static int char2addr_mask(char *arg, uint32_t *addr, uint32_t *mask)
510 struct addrinfo *ai;
511 char *smask=strrchr(arg,'/');
512 int len;
513 if (smask != NULL) {
514 *smask=0;
515 smask++;
517 if (getaddrinfo(arg,NULL,NULL,&ai) != 0)
518 return -1;
519 else {
520 if (ai->ai_family == AF_INET) {
521 struct sockaddr_in *ip4addr=(struct sockaddr_in *) ai->ai_addr;
522 len=4;
523 if (smask != NULL)
524 n2mask(len,atoi(smask),mask);
525 else
526 n2mask(len,32,mask);
527 addr[0]=ip4addr->sin_addr.s_addr & mask[0];
528 } else if (ai->ai_family == AF_INET6) {
529 int i;
530 struct sockaddr_in6 *ip6addr=(struct sockaddr_in6 *) ai->ai_addr;
531 len=16;
532 if (smask != NULL)
533 n2mask(len,atoi(smask),mask);
534 else
535 n2mask(len,128,mask);
536 for (i=0;i<4;i++)
537 addr[i]=*(((uint32_t *)ip6addr->sin6_addr.s6_addr)+i) & mask[i];
538 } else
539 len=-1;
540 freeaddrinfo(ai);
541 return len;
545 /* user interface: add an ipv4 or ipv6 range */
546 static int iplogadd(char *arg)
548 uint32_t addr[4],mask[4];
549 int len=char2addr_mask(arg,addr,mask);
550 if (len == 4)
551 return iplog4radd(&ip4loghead,addr[0],mask[0]);
552 else if (len == 16)
553 return iplog6radd(&ip6loghead,addr,mask);
554 else
555 return EINVAL;
558 /* user interface: delete an ipv4 or ipv6 range */
559 static int iplogdel(char *arg)
561 uint32_t addr[4],mask[4];
562 int len=char2addr_mask(arg,addr,mask);
563 if (len == 4)
564 return iplog4rdel(&ip4loghead,addr[0],mask[0]);
565 else if (len == 16)
566 return iplog6rdel(&ip6loghead,addr,mask);
567 else
568 return EINVAL;
571 /* list the ipv4 ranges */
572 static void iplog4rlist(struct ip4logaddr *ph, FILE *fd)
574 if (ph != NULL) {
575 char hostname[20];
576 if (ip42string(&ph->addr,hostname,sizeof(hostname)) == 0)
577 printoutc(fd," ipv4: %s/%d",hostname,mask2n(4,&ph->mask));
578 iplog4rlist(ph->next,fd);
582 /* list the ipv6 ranges */
583 static void iplog6rlist(struct ip6logaddr *ph, FILE *fd)
585 if (ph != NULL) {
586 char hostname[100];
587 if (ip62string(ph->addr,hostname,sizeof(hostname)) == 0)
588 printoutc(fd," ipv6: %s/%d",hostname,mask2n(16,&ph->mask));
589 iplog6rlist(ph->next,fd);
593 /* user interfaces list the ip ranges (v4 and v6)*/
594 static int iploglist(FILE *fd)
596 iplog4rlist(ip4loghead,fd);
597 iplog6rlist(ip6loghead,fd);
598 return 0;
601 /* user interfaces set the garbage collection interval*/
602 int iplog_set_gc_interval(int p)
604 qtimer_del(ip_gc_timerno);
605 ip_gc_interval=p;
606 ip_gc_timerno=qtimer_add(ip_gc_interval,0,ip_hash_gc,NULL);
607 return 0;
610 /* user interfaces set the expire interval*/
611 int iplog_set_gc_expire(int e)
613 ip_gc_expire=e;
614 return 0;
617 /* print an item of the recent ip hash table */
618 static void iplog_iplist_item(struct ip_hash_entry *e, void *arg)
620 FILE *fd=arg;
621 char hostname[100];
622 if ((e->len==4 && ip42string((uint32_t *)e->ipaddr,hostname,sizeof(hostname))==0) ||
623 (e->len==16 && ip62string((uint32_t *)e->ipaddr,hostname,sizeof(hostname))==0)) {
624 struct passwd *pwd;
625 char *username;
626 if ((pwd=getpwuid(port_user(e->port))) == NULL)
627 username="(none)";
628 else
629 username=pwd->pw_name;
630 printoutc(fd,"ipv%d %s port=%d user=%s", (e->len==4)?4:6, hostname, e->port, username);
634 /* user interface: list all the ip addresses in the hash table */
635 static int iplog_iplist(FILE *fd)
637 ip_for_all_hash(iplog_iplist_item, fd);
638 return 0;
641 /* user interface: list the ip addresses on a specific port */
642 struct ipport_data {
643 FILE *fd;
644 int port;
647 static void iplog_ipport_item(struct ip_hash_entry *e, void *arg)
649 struct ipport_data *pipd=arg;
650 if (e->port == pipd->port)
651 iplog_iplist_item(e,pipd->fd);
654 static int iplog_ipport(FILE *fd,int port)
656 struct ipport_data ipd={fd, port};
657 ip_for_all_hash(iplog_ipport_item, &ipd);
658 return 0;
661 /* user interface: list the ip addresses of a specific user */
662 struct ipuser_data {
663 FILE *fd;
664 uid_t user;
667 static void iplog_ipuser_item(struct ip_hash_entry *e, void *arg)
669 struct ipuser_data *piud=arg;
670 if (port_user(e->port) == piud->user)
671 iplog_iplist_item(e,piud->fd);
674 static int iplog_ipuser(FILE *fd,char *user)
676 struct passwd *pwd;
677 struct ipuser_data iud={.fd=fd};
678 if (user==NULL || *user==0)
679 return EINVAL;
680 if (isdigit(*user))
681 pwd=getpwuid(atoi(user));
682 else
683 pwd=getpwnam(user);
684 if (pwd == NULL)
685 return EINVAL;
686 iud.user=pwd->pw_uid;
687 ip_for_all_hash(iplog_ipuser_item, &iud);
688 return 0;
691 /* user interface: search an ip address in the hash table */
692 static void iplog_ipsearch_item(int len,unsigned char *addr, FILE *fd)
694 struct ip_hash_entry *e;
695 int k = ip_hash(len, addr);
696 for(e = iph[k]; e && memcmp(e->ipaddr, addr, len) && e->len == len; e = e->next)
698 if(e != NULL)
699 iplog_iplist_item(e,fd);
702 static int iplog_ipsearch(FILE *fd,char *addr)
704 struct addrinfo *ai;
705 int rv=0;
706 if (addr==NULL || *addr==0)
707 return EINVAL;
708 if (getaddrinfo(addr,NULL,NULL,&ai) != 0)
709 return EINVAL;
710 if (ai->ai_family == AF_INET) {
711 struct sockaddr_in *ip4addr=(struct sockaddr_in *) ai->ai_addr;
712 iplog_ipsearch_item(4, (unsigned char *) &ip4addr->sin_addr.s_addr, fd);
713 } else if (ai->ai_family == AF_INET6) {
714 struct sockaddr_in6 *ip6addr=(struct sockaddr_in6 *) ai->ai_addr;
715 iplog_ipsearch_item(16, ip6addr->sin6_addr.s6_addr , fd);
716 } else
717 rv=EINVAL;
718 freeaddrinfo(ai);
719 return rv;
722 /* command list */
723 static struct comlist cl[]={
724 {"iplog","============","IP/Mac/User Logging",NULL,NOARG},
725 {"iplog/showinfo","","Show info on logging",ipshowinfo,NOARG|WITHFILE},
726 {"iplog/logfile","pathname","Set the logfile",iplogfile,STRARG},
727 {"iplog/ipadd","ipaddr/mask","add an ipv4/v6 range",iplogadd,STRARG},
728 {"iplog/ipdel","ipaddr/mask","del an ipv6/v6 range",iplogdel,STRARG},
729 {"iplog/list","","list ip ranges",iploglist,NOARG|WITHFILE},
730 {"iplog/setgcint","N","change garbage collector interval",iplog_set_gc_interval,INTARG},
731 {"iplog/setexpire","N","change iplog entries expire time",iplog_set_gc_expire,INTARG},
732 {"iplog/iplist","","list active IP",iplog_iplist,NOARG|WITHFILE},
733 {"iplog/ipport","port","list active IP on a port",iplog_ipport,INTARG|WITHFILE},
734 {"iplog/ipuser","user","list active IP of a user",iplog_ipuser,STRARG|WITHFILE},
735 {"iplog/ipsearch","ipaddr","search an IP address",iplog_ipsearch,STRARG|WITHFILE},
738 static int iplog_hup(struct dbgcl *event,void *arg,va_list v)
740 if (logfilefd >= 0) {
741 char stime[26];
742 char lf[]="\n";
743 char *prehup="SIGHUP: closing file";
744 char *posthup="SIGHUP: opening file";
745 struct iovec preiov[]={{stime+4,16},{prehup,strlen(prehup)},{lf,1}};
746 struct iovec postiov[]={{stime+4,16},{posthup,strlen(posthup)},{lf,1}};
747 time_t ntime=time(&ntime);
748 ctime_r(&ntime,stime);
749 writev(logfilefd,preiov,3);
750 close(logfilefd);
751 logfilefd=open(logfile,O_CREAT|O_WRONLY|O_APPEND,0600);
752 writev(logfilefd,postiov,3);
754 return 0;
757 static void
758 __attribute__ ((constructor))
759 init (void)
761 iph=calloc(IP_HASH_SIZE,sizeof(struct ip_hash_entry *));
762 ADDCL(cl);
763 ADDDBGCL(dl);
764 ip_gc_timerno=qtimer_add(ip_gc_interval,0,ip_hash_gc,NULL);
765 eventadd(iplog_hup, "sig/hup", NULL);
766 eventadd(iplog_pktin, "packet/in", NULL);
767 eventadd(iplog_port_minus, "port/-", NULL);
770 static void
771 __attribute__ ((destructor))
772 fini (void)
774 time_t t = qtime();
775 closelogfile();
776 eventdel(iplog_port_minus, "port/-", NULL);
777 eventdel(iplog_pktin, "packet/in", NULL);
778 eventdel(iplog_hup, "sig/hup", NULL);
779 qtimer_del(ip_gc_timerno);
780 DELCL(cl);
781 DELDBGCL(dl);
782 ip_for_all_hash(ip_gc, &t);
783 free(iph);