OSDN Git Service

Fix no pic
[uclinux-h8/uClinux-dist.git] / user / diald / firewall.c
1 /*
2  * firewall.c - Packet filtering for diald.
3  *
4  * Copyright (c) 1994, 1995, 1996 Eric Schenk.
5  * All rights reserved. Please see the file LICENSE which should be
6  * distributed with this software for terms of use.
7  */
8
9 #include "diald.h"
10
11 static FW_unit units[FW_NRUNIT];
12 static int initialized = 0;
13 int impulse_init_time = 0;
14 int impulse_time = 0;
15 int impulse_fuzz = 0;
16
17 void del_connection(FW_Connection *);
18
19 /*
20  * Initialize the units.
21  */
22
23 static void init_units(void)
24 {
25     int i;
26
27     for (i = 0; i < FW_NRUNIT; i++) {
28         units[i].used = 0;
29         units[i].filters = NULL;
30         units[i].last = NULL;
31         units[i].connections = malloc(sizeof(FW_Connection));
32         units[i].nrules = 0;
33         units[i].nfilters = 0;
34         if (!units[i].connections) {
35             syslog(LOG_ERR,"Out of memory! AIIEEE!");
36             die(1);
37         }
38         units[i].connections->next = units[i].connections->prev
39             = units[i].connections;
40     }
41     initialized = 1;
42 }
43
44 /* is the time given by "clock" in the given slot? */
45
46 static unsigned int in_slot(FW_Timeslot *slot, time_t *clock)
47 {
48     struct tm *ltime = localtime(clock);
49     int ctime = ltime->tm_hour*60*60+ltime->tm_min*60+ltime->tm_sec; 
50
51 #if 0
52     syslog(LOG_INFO,"slot check: %d %d %d %d",
53         ltime->tm_sec+ltime->tm_min*60+ltime->tm_hour*60*60, ltime->tm_wday,
54         ltime->tm_mday, ltime->tm_mon);
55 #endif
56
57     while (slot) {
58 #if 0
59     syslog(LOG_INFO,"slot def: %d %d %x %x %x",
60         slot->start, slot->end, slot->wday, slot->mday, slot->month);
61 #endif
62         if ((slot->start <= ctime)
63         &&  (ctime <= slot->end)
64         &&  (slot->wday & (1<<ltime->tm_wday))
65         &&  (slot->mday & (1<<(ltime->tm_mday-1)))
66         &&  (slot->month & (1<<ltime->tm_mon))) {
67             return 1;
68         }
69         slot = slot->next;
70     }
71
72     return 0;
73 }
74
75
76 /*
77  * return 0 if the given time is in the given slots active time set.
78  * Otherwise return the number of seconds until the slot is next active, or
79  * the number of seconds until the next occurance of 00:00 hours, whichever
80  * comes first.
81  */
82
83 static unsigned int slot_start_timeout(FW_Timeslot *slot, time_t *clock)
84 {
85     struct tm *ltime = localtime(clock);
86     int ctime, mintime;
87
88     if (in_slot(slot,clock)) return 0;
89
90     /* Ok, we are currently NOT in this slot's time range. */
91
92     ctime = ltime->tm_hour*60*60 + ltime->tm_min*60 + ltime->tm_sec;
93     mintime =  24*60*60 - ctime;
94
95     while (slot) {
96         if ((slot->wday & (1<<ltime->tm_wday))
97         && (slot->mday & (1<<(ltime->tm_mday-1)))
98         && (slot->month & (1<<ltime->tm_mon))
99         && (slot->start >= ctime)) {
100             /* Ok, this slot disjunct occurs today */
101             if (mintime >= (slot->start - ctime))
102                 mintime = slot->start - ctime;
103         }
104         slot = slot->next;
105     }
106
107     return mintime;
108 }
109
110 /*
111  * return 0 if the given time is not in the given slots active time set.
112  * Otherwise return the number of seconds until the slot times out, or
113  * the number of seconds until the next occurance of 00:00 hours, whichever
114  * comes first.
115  */
116
117 static unsigned int slot_end_timeout(FW_Timeslot *slot, time_t *clock)
118 {
119     struct tm *ltime = localtime(clock);
120     int ctime, maxtime;
121
122     if (!in_slot(slot,clock)) return 0;
123
124     /* Ok, we are currently in this slot's time range. */
125
126     ctime = ltime->tm_hour*60*60 + ltime->tm_min*60 + ltime->tm_sec;
127     maxtime = -1;
128
129     while (slot) {
130         if ((slot->wday & (1<<ltime->tm_wday))
131         && (slot->mday & (1<<(ltime->tm_mday-1)))
132         && (slot->month & (1<<ltime->tm_mon))
133         && (slot->start <= ctime)
134         && (ctime <= slot->end)) {
135             /* Ok, this slot disjunct is active now */
136             int t = slot->end - ctime;
137             if (maxtime <= t)
138                 maxtime = t;
139         }
140         slot = slot->next;
141     }
142
143     if (maxtime == -1)
144         return 24*60*60 - ctime;
145     else
146         return maxtime;
147 }
148
149 /* Find a connection in the queue */
150 static FW_Connection *find_connection(FW_unit *unit, FW_ID *id)
151 {
152     FW_Connection *c = unit->connections->next;
153
154     /* look for a connection that matches this one */
155     while (c != unit->connections) {
156         if (memcmp((unsigned char *)&c->id,
157                 (unsigned char *)id,sizeof(FW_ID))==0)
158            break;
159         c = c->next;
160     }
161     if (c == unit->connections) {
162         return 0;
163     } else {
164         return c;
165     }
166 }
167
168 /*
169  * Add/update a connection in the queue.
170  */
171
172 static void add_connection(
173     FW_unit *unit, FW_Connection *c, FW_ID *id, unsigned int timeout, TCP_STATE lflags)
174 {
175     /* look for a connection that matches this one */
176     if (c == NULL) {
177         if (timeout > 0) {
178             /* no matching connection, add one */
179             c = malloc(sizeof(FW_Connection));
180             if (c == 0) {
181                syslog(LOG_ERR,"Out of memory! AIIEEE!");
182                die(1);
183             }
184             c->id = *id;
185             init_timer(&c->timer);
186             c->tcp_state = lflags;
187             c->unit = unit;
188             c->timer.data = (int)c;
189             c->timer.function = (void *)(int)del_connection;
190             c->next = unit->connections->next;
191             c->prev = unit->connections;
192             unit->connections->next->prev = c;
193             unit->connections->next = c;
194             c->timer.expires = timeout;
195             add_timer(&c->timer);
196             if (debug&DEBUG_CONNECTION_QUEUE)
197                 syslog(LOG_INFO,"Adding connection %d @ %ld - timeout %d",(int)c,
198                         time(0),timeout);
199         }
200     } else {
201         /* found a matching connection, toss it's old timer */
202         if (timeout > 0) {
203             /* reanimating a ghost? */
204             del_timer(&c->timer);
205             c->timer.expires = timeout;
206             add_timer(&c->timer);
207             if (debug&DEBUG_CONNECTION_QUEUE)
208                 syslog(LOG_INFO,"Adding connection %d @ %ld - timeout %d",(int)c,
209                         time(0),timeout);
210         } else {
211             /* timeout = 0, so toss the connection */
212             del_timer(&c->timer);
213             del_connection(c);
214         }
215     }
216 }
217
218 /*
219  * Get a connection out of a queue.
220  */
221
222 void del_connection(FW_Connection *c)
223 {
224     if (debug&DEBUG_CONNECTION_QUEUE)
225         syslog(LOG_INFO,"Deleting connection %d @ %ld",(int)c,time(0));
226
227     c->next->prev = c->prev;
228     c->prev->next = c->next;
229     free(c);
230 }
231
232 void del_impulse(FW_unit *unit)
233 {
234
235     if (unit->impulse_mode) {
236         unit->impulse_mode = 0;
237         if (impulse_time > 0) {
238             unit->impulse.data = (int)unit;
239             unit->impulse.function = (void *)(int)del_impulse;
240             unit->impulse.expires = impulse_time;
241             if (debug&DEBUG_CONNECTION_QUEUE)
242                 syslog(LOG_INFO,"Refreshing impulse generator: mode %d, time %ld @ %ld",unit->impulse_mode,unit->impulse.expires,time(0));
243             add_timer(&unit->impulse);
244         }
245     } else {
246         unit->impulse_mode = 1;
247         impulse_init_time = 0;  /* zero the initial impulse time */
248         if (impulse_fuzz > 0) {
249             unit->impulse.data = (int)unit;
250             unit->impulse.function = (void *)(int)del_impulse;
251             unit->impulse.expires = impulse_fuzz;
252             if (debug&DEBUG_CONNECTION_QUEUE)
253                 syslog(LOG_INFO,"Refreshing impulse generator: mode %d, time %ld @ %ld",unit->impulse_mode,unit->impulse.expires,time(0));
254             add_timer(&unit->impulse);
255         }
256     }
257 }
258
259 /* Check if a forcing rule currently applies to the connection */
260
261 static void fw_force_update(FW_unit *unit)
262 {
263     FW_Filters *fw;
264     int timeout, mintime;
265     time_t clock = time(0);
266
267     /* check if the current forcing slot has expired */
268     if (unit->force_etime > clock) return;
269
270     fw = unit->filters;
271     mintime = 24*60*60;
272     unit->force = 0;
273
274     while (fw) {
275         if (fw->filt.type == FW_TYPE_UP || fw->filt.type == FW_TYPE_DOWN) {
276             /* check when the rule is next applicable */
277             timeout = slot_start_timeout(fw->filt.times,&clock);
278         
279             if (timeout > 0) {
280                 /* first time at which a previous slot starts */
281                 if (timeout < mintime)
282                     mintime = timeout;
283                 goto next_rule;
284             } else {
285                 /* time at which the current slot ends */
286                 timeout = slot_end_timeout(fw->filt.times,&clock);
287                 if (timeout < mintime)
288                     mintime = timeout;
289             }
290         } else
291             goto next_rule;
292
293         if (fw->filt.type == FW_TYPE_UP)
294             unit->force = 1;
295         else
296             unit->force = 2;
297
298         break;
299
300 next_rule: /* try the next filter */
301         fw = fw->next;
302     }
303
304     unit->force_etime = clock + mintime;
305 }
306
307 /* Check if an impulse rule currently applies to the connection */
308
309 static void fw_impulse_update(FW_unit *unit, int force)
310 {
311     FW_Filters *fw;
312     int timeout, mintime, itimeout, ifuzz, ftimeout;
313     time_t clock = time(0);
314
315     /* check if the current forcing slot has expired */
316     if (clock < unit->impulse_etime && !force) return;
317
318     fw = unit->filters;
319     mintime = 24*60*60;
320     itimeout = 0;
321     ftimeout = 0;
322     ifuzz = 0;
323
324     while (fw) {
325         if (fw->filt.type == FW_TYPE_IMPULSE) {
326             /* check when the rule is next applicable */
327             timeout = slot_start_timeout(fw->filt.times,&clock);
328             if (timeout > 0) {
329                 /* Will be applicable soon */
330                 /* first time at which a previous slot starts
331                  * (i.e. schedule changes) */
332                 if (timeout < mintime)
333                     mintime = timeout;
334                 goto next_rule;
335             } else {
336                 /* time at which the current slot ends */
337                 timeout = slot_end_timeout(fw->filt.times,&clock);
338                 ifuzz = fw->filt.fuzz;
339                 itimeout = fw->filt.timeout;
340                 ftimeout = fw->filt.timeout2;
341                 if (timeout < mintime)
342                     mintime = timeout;
343             }
344         } else
345             goto next_rule;
346
347         break;
348
349 next_rule: /* try the next filter */
350         fw = fw->next;
351     }
352     unit->impulse_etime = clock + mintime;
353
354     del_timer(&unit->impulse);
355     if (unit->up && (itimeout > 0 || (force && ftimeout > 0))) {
356         /* place the current impulse generator into the impulse queue */
357         impulse_time = itimeout;
358         impulse_init_time = ftimeout;
359         impulse_fuzz = ifuzz;
360         unit->impulse_mode = 0;
361         unit->impulse.data = (int)unit;
362         unit->impulse.function = (void *)(int)del_impulse;
363         unit->impulse.expires = (force)?ftimeout:itimeout;
364         add_timer(&unit->impulse);
365         if (debug&DEBUG_CONNECTION_QUEUE)
366             syslog(LOG_INFO,"Refreshing impulse generator: mode %d, time %ld @ %ld",unit->impulse_mode,unit->impulse.expires,time(0));
367     }
368 }
369
370 static void log_packet(int accept, struct iphdr *pkt, int len,  int rule)
371 {
372     char saddr[20], daddr[20];
373     struct in_addr addr;
374     int sport = 0, dport = 0;
375     struct tcphdr *tcp = (struct tcphdr *)((char *)pkt + 4*pkt->ihl);
376     struct udphdr *udp = (struct udphdr *)tcp;
377
378     addr.s_addr = pkt->saddr;
379     strcpy(saddr,inet_ntoa(addr));
380     addr.s_addr = pkt->daddr;
381     strcpy(daddr,inet_ntoa(addr));
382
383     if (pkt->protocol == IPPROTO_TCP || pkt->protocol == IPPROTO_UDP)
384         sport = ntohs(udp->source), dport = ntohs(udp->dest);
385
386     if (pkt->protocol == IPPROTO_TCP) {
387         syslog(LOG_INFO,
388             "filter %s rule %d proto %d len %d seq %lx ack %lx flags %s%s%s%s%s%s packet %s,%d => %s,%d",
389             (accept)?"accepted":"ignored",rule,
390             pkt->protocol,
391             ntohs(pkt->tot_len),
392             ntohl(tcp->seq), ntohl(tcp->ack_seq),
393             (tcp->fin) ? " FIN" : "",
394             (tcp->syn) ? " SYN" : "",
395             (tcp->rst) ? " RST" : "",
396             (tcp->psh) ? " PUSH" : "",
397             (tcp->ack) ? " ACK" : "",
398             (tcp->urg) ? " URG" : "",
399             saddr, sport, daddr, dport);
400     } else {
401         syslog(LOG_INFO,
402             "filter %s rule %d proto %d len %d packet %s,%d => %s,%d",
403             (accept)?"accepted":"ignored",rule,
404             pkt->protocol,
405             htons(pkt->tot_len),
406             saddr, sport, daddr, dport);
407     }
408 }
409
410 /* Check if we need to reorder IP addresses for cannonical ordering */
411 static int ip_direction(struct iphdr *pkt)
412 {
413     struct udphdr *udp = (struct udphdr *)((char *)pkt + 4*pkt->ihl);
414     if (ntohl(pkt->saddr) > ntohl(pkt->daddr)
415     || (ntohl(pkt->saddr) == ntohl(pkt->daddr) &&
416        (pkt->protocol == IPPROTO_TCP || pkt->protocol == IPPROTO_UDP)
417        && ntohs(udp->source) > ntohs(udp->dest)))
418         return 2;
419     else
420         return 1;
421 }
422
423 static void ip_swap_addrs(struct iphdr *pkt)
424 {
425     struct udphdr *udp = (struct udphdr *)((char *)pkt + 4*pkt->ihl);
426     unsigned long taddr;
427     unsigned short tport;
428     if (pkt->protocol == IPPROTO_TCP || pkt->protocol == IPPROTO_UDP) {
429         tport = udp->source;
430         udp->source = udp->dest;
431         udp->dest = tport;
432     } 
433     taddr = pkt->saddr;
434     pkt->saddr = pkt->daddr;
435     pkt->daddr = taddr;
436 }
437
438 void print_filter(FW_Filter *filter)
439 {
440     int i;
441     syslog(LOG_INFO,"filter: prl %d log %d type %d cnt %d tm %d",
442         filter->prule,filter->log,filter->type,
443         filter->count,filter->timeout);
444     for (i = 0; i < filter->count; i++) {
445         syslog(LOG_INFO,"    term: shift %d op %d off %d%c msk %x tst %x",
446             filter->terms[i].shift, filter->terms[i].op,
447             filter->terms[i].offset&0x7f,
448             (filter->terms[i].offset&0x80)?'d':'h',
449             filter->terms[i].mask, filter->terms[i].test);
450     }
451 }
452
453 /* Check if a packet passes the filters */
454 int check_firewall(int unitnum, unsigned char *pkt, int len)
455 {
456     FW_unit *unit;
457     FW_Filters *fw;
458     unsigned char *data;
459     FW_ProtocolRule *prule, *pprule = 0;
460     FW_Term *term;
461     int i,v,rule;
462     int direction,opdir;
463     TCP_STATE lflags;
464     clock_t clock = time(0);
465     FW_ID id;
466     FW_Connection *conn;
467     struct iphdr * ip_pkt = (struct iphdr *)pkt;
468
469     if (!initialized) init_units();
470
471     if (unitnum < 0 || unitnum >= FW_NRUNIT) {
472         /* FIXME: set an errorno? */
473         return -1;
474     }
475
476     unit = &units[unitnum];
477     fw = unit->filters;
478
479     data = pkt + 4*((struct iphdr *)pkt)->ihl;
480
481     /* Find the correct protocol rule */
482     for (i = 0; i < unit->nrules; i++) {
483         pprule = &unit->prules[i];
484         if (FW_PROTO_ALL(pprule->protocol)
485         || pprule->protocol == ip_pkt->protocol)
486         break;
487     }
488
489     if (pprule == 0) {
490         return -1;      /* No protocol rules? */
491     }
492
493     /* Build the connection ID, and set the direction flag */
494     direction = ip_direction(ip_pkt);
495     if (direction == 2) ip_swap_addrs(ip_pkt);
496     for (i = 0; i < FW_ID_LEN; i++)
497         id.id[i] = (FW_IN_DATA(pprule->codes[i])?data:pkt)
498                     [FW_OFFSET(pprule->codes[i])];
499     if (direction == 2) ip_swap_addrs(ip_pkt);
500     conn = find_connection(unit,&id);
501     opdir = (direction==1)?2:1;
502
503     /* Do the TCP liveness changes */
504     if (ip_pkt->protocol == IPPROTO_TCP) {
505         struct tcphdr *tcp = (struct tcphdr *)((char *)ip_pkt + 4*ip_pkt->ihl);
506         int tcp_data_len = len - (4*ip_pkt->ihl + sizeof(struct tcphdr));
507
508         if (conn) {
509             lflags = conn->tcp_state;
510         } else {
511             lflags.fin_seq[0] = lflags.fin_seq[1] = 0;
512             lflags.tcp_flags = 0;
513             lflags.saw_fin = 0;
514         }
515         if (tcp->rst) {
516             lflags.saw_fin = 0;
517             lflags.tcp_flags = 0;
518         } else if (tcp->fin) {
519             lflags.saw_fin |= direction;
520             lflags.fin_seq[direction-1] = ntohl(tcp->seq)+tcp_data_len+1;
521         } else if (tcp->syn || tcp_data_len > 0) {
522             /* Either we have a SYN packet, or we have a data carrying
523              * packet. In either case we want to declare this direction live.
524              * FIXME. It is possible that this should set saw_fin to 0 in the
525              * case that we have a SYN packet.
526              */
527             lflags.saw_fin &= ~direction;
528             lflags.tcp_flags |= direction;
529         }
530         if ((lflags.saw_fin & opdir) && (tcp->ack)) {
531             if (lflags.fin_seq[opdir-1] == ntohl(tcp->ack_seq)) {
532                 lflags.tcp_flags &= ~direction;
533             }
534         }
535
536         if (conn) {
537             conn->tcp_state = lflags;
538         }
539     }
540
541     rule = 1;
542     while (fw) {
543 #if 0
544         print_filter(&fw->filt);
545 #endif
546         /* is this rule currently applicable? */
547         if ((unit->up && fw->filt.type == FW_TYPE_BRINGUP)
548            || (!unit->up && fw->filt.type == FW_TYPE_KEEPUP)
549            || !in_slot(fw->filt.times,&clock)
550            || fw->filt.type == FW_TYPE_IMPULSE
551            || fw->filt.type == FW_TYPE_UP
552            || fw->filt.type == FW_TYPE_DOWN)
553             goto next_rule;
554
555         /* Check the protocol rule */
556         prule = &unit->prules[fw->filt.prule];
557         if (!(FW_PROTO_ALL(prule->protocol)
558         || prule->protocol == ip_pkt->protocol))
559             goto next_rule;
560
561         /* Check the terms */
562         for (i = 0;
563         (fw->filt.count > FW_MAX_TERMS) || (i < fw->filt.count); i++) {
564             if (i > FW_MAX_TERMS && fw->filt.count == 0) {
565                 fw = fw->next, i = 0;
566                 if (fw == NULL) break;
567             }
568             term = &fw->filt.terms[i];
569             if (FW_TCP_STATE(term->offset))
570                 v = (lflags.tcp_flags >> term->shift) && term->mask;
571             else
572                 v = (ntohl(*(int *)(&(FW_IN_DATA(term->offset)?data:pkt)
573                                   [FW_OFFSET(term->offset)]))
574                     >> term->shift) & term->mask;
575 #if 0
576             syslog(LOG_INFO,"testing ip %x:%x data %x:%x mask %x shift %x test %x v %x",
577                 ntohl(*(int *)(&pkt[FW_OFFSET(term->offset)])),
578                 *(int *)(&pkt[FW_OFFSET(term->offset)]),
579                 ntohl(*(int *)(&data[FW_OFFSET(term->offset)])),
580                 *(int *)(&data[FW_OFFSET(term->offset)]),
581                 term->mask,
582                 term->shift,
583                 term->test,
584                 v);
585 #endif
586             switch (term->op) {
587             case FW_EQ: if (v != term->test) goto next_rule; break;
588             case FW_NE: if (v == term->test) goto next_rule; break;
589             case FW_GE: if (v < term->test) goto next_rule; break;
590             case FW_LE: if (v > term->test) goto next_rule; break;
591             }
592         }
593         /* Ok, we matched a rule. What are we suppose to do? */
594 #if 0
595         if (fw->filt.log)
596 #endif
597         if (debug&DEBUG_FILTER_MATCH)
598             log_packet(fw->filt.type!=FW_TYPE_IGNORE,ip_pkt,len,rule);
599
600         /* Check if this entry goes into the queue or not */
601         if (fw->filt.type != FW_TYPE_IGNORE && fw->filt.type != FW_TYPE_WAIT) {
602             add_connection(unit,conn,&id,fw->filt.timeout,lflags);
603         }
604         /* check if we are no longer waiting */
605         if (fw->filt.type == FW_TYPE_WAIT) {
606                 unit->waiting = 0;
607                 /* WAITING rules don't do the final match, but
608                  * must occur before other rules
609                  */
610                 goto next_rule;
611         }
612
613         /* Return 1 if accepting rule with non zero timeout, 0 otherwise */
614         return ((fw->filt.type != FW_TYPE_IGNORE || fw->filt.type != FW_TYPE_WAIT) && fw->filt.timeout > 0);
615
616 next_rule: /* try the next filter */
617         fw = fw->next;
618         rule++;
619     }
620     /* Failed to match any rule. This means we ignore the packet */
621     if (debug&DEBUG_FILTER_MATCH)
622         log_packet(0,ip_pkt,len,0);
623     return 1;
624 }
625
626 static void pcountdown(int level, long secs)
627 {
628     char buf[10];
629     sprintf(buf,"%02ld:%02ld:%02ld\n",secs/3600,(secs/60)%60,secs%60);
630     if (monitors) mon_write(level,buf,9);
631 }
632
633 int ctl_firewall(int op, struct firewall_req *req)
634 {
635     FW_unit *unit;
636     if (!initialized) init_units();
637
638     /* Need to check that req is OK */
639
640     if (req && req->unit >= FW_NRUNIT) return -1; /* ERRNO */
641
642     if (req) unit = &units[req->unit];
643     else unit = units;
644     
645     switch (op) {
646     case IP_FW_QFLUSH:
647         if (!req) return -1; /* ERRNO */
648         {
649             FW_Connection *c,*cn;
650             for (c = unit->connections->next;
651             c != unit->connections; c = cn) {
652                 cn = c->next;
653                 del_timer(&c->timer);
654                 c->next->prev = c->prev;
655                 c->prev->next = c->next;
656                 free((void *)c);
657             }
658             return 0;
659         }
660     case IP_FW_QCHECK:
661         if (!req) return -1; /* ERRNO */
662         
663         fw_force_update(unit);
664         fw_impulse_update(unit,0);
665
666         return (unit->force == 2
667                 || (unit->force == 0
668                     && !(unit->up && unit->impulse_mode == 0
669                          && (impulse_init_time > 0 || impulse_time > 0))
670                     && unit->connections == unit->connections->next));
671
672
673     case IP_FW_PFLUSH:
674         if (!req) return -1; /* ERRNO */
675         unit->nrules = 0;
676         return 0;
677     /* PFLUSH implies FFLUSH */
678     case IP_FW_FFLUSH:
679         if (!req) return -1; /* ERRNO */
680         {
681             FW_Filters *next, *filt = unit->filters;
682             while (filt)
683                 { next = filt->next; free(filt); filt = next; }
684             unit->filters = NULL;
685             unit->last = NULL;
686         }
687         return 0;
688     case IP_FW_AFILT:
689         if (!req) return -1; /* ERRNO */
690         {
691             FW_Filters *filters = malloc(sizeof(FW_Filters));
692             if (filters == 0) {
693                 syslog(LOG_ERR,"Out of memory! AIIEEE!");
694                 return -1; /* ERRNO */
695             }
696             filters->next = 0;
697             filters->filt = req->fw_arg.filter;
698             if (unit->last) unit->last->next = filters;
699             if (!unit->filters) unit->filters = filters;
700             unit->last = filters;
701             unit->nfilters++;
702         }
703         return 0;
704     case IP_FW_APRULE:
705         if (!req) return -1; /* ERRNO */
706         if (unit->nrules >= FW_MAX_PRULES) return -1; /* ERRNO */
707         unit->prules[(int)unit->nrules] = req->fw_arg.rule;
708         return unit->nrules++;
709     /* Printing does nothing right now */
710     case IP_FW_PCONN:
711         if (!req) return -1; /* ERRNO */
712         {
713             unsigned long atime = time(0);
714             unsigned long tstamp = timestamp();
715             FW_Connection *c;
716             char saddr[20], daddr[20];
717             struct in_addr addr;
718             syslog(LOG_INFO,"up = %d, forcing = %d, impulse = %d, iitime = %d, itime = %d, ifuzz = %d, itimeout = %ld, timeout = %ld, next alarm = %d",
719                 unit->up,unit->force, unit->impulse_mode, impulse_init_time, impulse_time,
720                 impulse_fuzz,
721                 unit->impulse.expected-tstamp,unit->force_etime-atime,
722                 next_alarm());
723             for (c=unit->connections->next; c!=unit->connections; c=c->next) {
724                 if (c->timer.next == 0) c->timer.expected = tstamp;
725                 addr.s_addr = c->id.id[1] + (c->id.id[2]<<8)
726                         + (c->id.id[3]<<16) + (c->id.id[4]<<24);
727                 strcpy(saddr,inet_ntoa(addr));
728                 addr.s_addr = c->id.id[5] + (c->id.id[6]<<8)
729                         + (c->id.id[7]<<16) + (c->id.id[8]<<24);
730                 strcpy(daddr,inet_ntoa(addr));
731                 syslog(LOG_INFO,
732                         "ttl %ld, %d - %s/%d => %s/%d (tcp state ([%lx,%lx] %d,%d))",
733                         c->timer.expected-tstamp, c->id.id[0],
734                         saddr, c->id.id[10]+(c->id.id[9]<<8),
735                         daddr, c->id.id[12]+(c->id.id[11]<<8),
736                         c->tcp_state.fin_seq[0],
737                         c->tcp_state.fin_seq[1],
738                         c->tcp_state.saw_fin,
739                         c->tcp_state.tcp_flags);
740             }
741             return 0;
742         }
743         return 0;
744     case IP_FW_MCONN:
745         if (!req || !monitors) return -1; /* ERRNO */
746         {
747             unsigned long atime = time(0);
748             unsigned long tstamp = timestamp();
749             FW_Connection *c;
750             char saddr[20], daddr[20];
751             int sport, dport;
752             char proto[20];
753             struct protoent *pent;
754             struct in_addr addr;
755             char buf[1024];
756
757             sprintf(buf,"STATUS\n%d\n%d\n%d\n%d\n%d\n%d\n",
758                 unit->up, unit->force, unit->impulse_mode,
759                 impulse_init_time, impulse_time,
760                 impulse_fuzz);
761             if (monitors) mon_write(MONITOR_STATUS,buf,strlen(buf));
762
763             pcountdown(MONITOR_STATUS,(unit->impulse_mode)?(unit->impulse.expected-tstamp):0);
764             pcountdown(MONITOR_STATUS,unit->force_etime-atime);
765             pcountdown(MONITOR_STATUS,next_alarm());
766             if (monitors) mon_write(MONITOR_QUEUE,"QUEUE\n",6);
767             for (c=unit->connections->next; c!=unit->connections; c=c->next) {
768                 if (c->timer.next == 0) continue;
769                 addr.s_addr = c->id.id[1] + (c->id.id[2]<<8)
770                         + (c->id.id[3]<<16) + (c->id.id[4]<<24);
771                 strcpy(saddr,inet_ntoa(addr));
772                 addr.s_addr = c->id.id[5] + (c->id.id[6]<<8)
773                         + (c->id.id[7]<<16) + (c->id.id[8]<<24);
774                 strcpy(daddr,inet_ntoa(addr));
775 #ifdef EMBED
776                 pent = NULL;
777 #else
778                 pent = getprotobynumber(c->id.id[0]);
779 #endif
780                 if (pent) strcpy(proto,pent->p_name);
781                 else sprintf(proto,"%d",c->id.id[0]);
782                 sport = c->id.id[10]+(c->id.id[9]<<8);
783                 dport = c->id.id[12]+(c->id.id[11]<<8);
784                 sprintf(buf,
785                         "%-4s  %15s/%-5d  %15s/%-5d  ",
786                         proto, saddr, sport,
787                         daddr, dport);
788                 if (monitors) mon_write(MONITOR_QUEUE,buf,strlen(buf));
789                 pcountdown(MONITOR_QUEUE,c->timer.expected-tstamp);
790             }
791             if (monitors) mon_write(MONITOR_QUEUE,"END QUEUE\n",10);
792             return 0;
793         }
794         return 0;
795     case IP_FW_PPRULE:
796         if (!req) return -1; /* ERRNO */
797         return 0;
798     case IP_FW_PFILT:
799         if (!req) return -1; /* ERRNO */
800         return 0;
801     /* Opening and closing firewalls is cooperative right now.
802      * Also, it does nothing to change the behavior of a device
803      * associated with the firewall.
804      */
805     case IP_FW_OPEN:
806         {
807             int i;
808             for (i = 0; i < FW_NRUNIT; i++)
809                 if (units[i].used == 0) {
810                     struct firewall_req mreq;
811                     mreq.unit = i;
812                     ctl_firewall(IP_FW_PFLUSH,&mreq);
813                     units[i].used = 1;
814                     units[i].force_etime = 0;
815                     units[i].impulse_etime = 0;
816                     units[i].waiting = 1;
817                     return i;
818                 }
819             return -1;  /* ERRNO */
820         }
821     case IP_FW_CLOSE:
822         {
823             struct firewall_req mreq;
824             if (!req) return -1; /* ERRNO */
825             mreq.unit = req->unit;
826             ctl_firewall(IP_FW_PFLUSH,&mreq);
827             unit->used = 0;
828             return 0;
829         }
830     case IP_FW_UP:
831         unit->up = 1;
832         run_ip_up();
833         fw_force_update(unit);
834         fw_impulse_update(unit,1);
835         return 0;
836
837     case IP_FW_DOWN:
838         if (unit->up) run_ip_down();
839         unit->up = 0;
840         /* turn off the impulse generator */
841         del_timer(&unit->impulse);
842         return 0;
843     case IP_FW_WAIT:
844         return unit->waiting;
845     case IP_FW_RESET_WAITING:
846         unit->waiting = 1;
847         return 0;
848     }
849     return -1; /* ERRNO */
850 }