ah, need compat 9 to get hardening?
[debian/ipip] / run.c
1 /* run.c                The main command loop
2  *
3  * $Id: run.c,v 1.10 1995/03/19 17:21:06 bdale Exp $
4  *
5  * Copyright 1991, Michael Westerhof, Sun Microsystems, Inc.
6  * This software may be freely used, distributed, or modified, providing
7  * this header is not removed.
8  *
9  */
10
11 #include "ipip.h"
12
13 #include <time.h>
14 #include <sys/types.h>
15 #include <sys/time.h>
16 #include <sys/socket.h>
17 #include <netinet/in.h>
18 #include <netinet/in_systm.h>
19 #include <netinet/ip.h>
20 #include <netdb.h>
21 #include <fcntl.h>
22 #include <memory.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <errno.h>
26 #include <syslog.h>
27 extern int errno;
28
29 static int handle();
30 static int find_route();
31 static void tracer();
32
33 int martian_count = 3;
34 unsigned int martians[] = { 0x7f000001, 0xffffffff, 0x00000000 };
35
36 time_t last_send;
37 /* This is a loop counter for misc stuff.  We don't want to burden the
38    I/O system if we don't have to, so this is designed so that we will
39    be able to see if we have to print stats or fflush() no more often
40    than once per second if we are busy.  If we are idle, the time value
41    to the select() call will bring the delay up to 10 seconds.  So, the
42    stats output and the flush of stdio() should be within 10 seconds of
43    the correct time. */
44 #define SEND_CHECK_CNT 100;
45
46 /*
47  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
48  * Open all io, then start running it! 
49  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
50  */
51 int
52 run_it()
53 {
54         int i, j, nb, more_io, checker;
55         fd_set readfds;
56         struct timeval wait;
57
58         for(i=0;i<ifs_top;i++){
59                 if(ifs[i].type == IF_TYPE_NONE)continue;
60                 if(debugd)
61                     syslog(LOG_DEBUG,"opening interface %s",ifs[i].id);
62                 j = ifs[i].ifopen(&ifs[i]);
63                 if(j<0)return j;
64         }
65
66         if(debugd)
67             syslog(LOG_DEBUG,"initialization complete");
68
69         last_send = time(NULL);
70         checker = 0;
71
72         for(;;){
73
74                 FD_ZERO(&readfds);
75
76                 more_io = 0;
77
78                 for(i=0;i<ifs_top;i++){
79                         if((ifs[i].type != IF_TYPE_NONE) &&
80                            (ifs[i].status & IF_STAT_OPEN)){
81                                 FD_SET(ifs[i].fd, &readfds);
82                                 if(ifs[i].status & IF_STAT_CALL_AGAIN)more_io++;
83                         }
84                 }
85
86                 if(more_io){
87                         wait.tv_sec =  0;       /* Don't wait long! */
88                         wait.tv_usec = 10000;   /* 10 msecs if chars in buffer */
89                 } else {
90                         wait.tv_sec =  10;      /* lets keep things going... */
91                         wait.tv_usec = 0;       /* but slowly is ok */
92                         checker = 0;            /* make sure we check the time */
93                 }
94
95                 nb = select(FD_SETSIZE,&readfds,(fd_set *)0,(fd_set *)0,&wait);
96
97                 if(nb < 0){
98                         if(errno == EINTR)continue;     /* Ignore this error */
99                         PERR("select in run_it()");
100                         return -1;
101                 }
102
103                 for(i=0;i<ifs_top;i++){
104                         if((ifs[i].type != IF_TYPE_NONE) &&
105                            (ifs[i].status & IF_STAT_OPEN)){
106                                 if(FD_ISSET(ifs[i].fd, &readfds) ||
107                                   (ifs[i].status & IF_STAT_CALL_AGAIN)){
108                                         if(handle(&ifs[i])<0) {
109                                                 PERR("handle in run_it()");
110                                                 return -1;
111                                         }
112                                 }
113                         }
114                 } /* for each interface */
115
116                 if(checker <= 0){
117                         send_stats(0);                  /* see if we must */
118                         checker = SEND_CHECK_CNT;       /* reset counter */
119                 } else {
120                         checker--;
121                 }
122
123         } /* forever */
124 }
125
126 /*
127  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
128  * Handle the read/route/send stuff
129  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
130  */
131 static int
132 handle(ifp)
133 struct interface *ifp;
134 {
135         struct message m;
136         int n;
137 #ifdef AMPRONLY
138         unsigned int srcip, dstip;
139 #endif
140
141         m.length = 0;
142         m.from_if = ifp;
143         m.to_if = NULL;
144         m.fip = 0;
145         m.tip = 0;
146         m.fport = 0;
147         m.tport = 0;
148
149         n = ifp->ifread(ifp, &m);
150         if(n <= 0) return n;            /* error or packet not yet complete */
151
152         m.from_if->in++;
153
154         if(find_route(&m) < 0) {
155                 PERR("find_route() failed in handle()");
156                 return -1;
157         }
158
159 #ifdef AMPRONLY
160         /* this is a really, really rude hack... it will prevent any frames
161            from being switched that have source or destination outside of 
162            net 44 */
163
164         (void)memcpy( (char *)&srcip, (char *)m.msg + 12, 4);
165         (void)memcpy( (char *)&dstip, (char *)m.msg + 16, 4);
166
167 #ifdef notdef
168         syslog(LOG_DEBUG,"from ip %lx, to ip %lx", srcip, dstip);
169 #endif
170
171         if ((( srcip & 0xff ) != 44) || 
172             (( dstip & 0xff ) != 44)) {
173                 m.to_if=NULL;                   /* drop frame on the floor */
174                 if(debugt)tracer(&m);           /* Trace the message */
175                 return 0;                       /* No route found */
176         }
177 #endif
178
179 #ifndef BDALE
180         /* if this is Bdale's compilation, we need to be able to go back out
181            the same interface! */
182         if(m.from_if==m.to_if){
183                 m.to_if=NULL;                   /* Can't go out same iface! */
184                 m.from_if->looped_in++;
185         }
186 #endif
187
188         if(debugt)tracer(&m);                   /* Trace the message */
189
190         if(m.to_if==NULL) {
191                 PERR("route not found in handle()");
192                 return 0;               /* No route found */
193         }
194
195         if (m.to_if->ifsend(m.to_if, &m) < 0) {
196                 PERR("ifsend() failed in handle()");
197                 return -1;
198         }
199         m.to_if->out++;
200
201         return 1;
202 }       
203
204 /*
205  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
206  * Print a trace of a message
207  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
208  */
209 static void
210 tracer(m)
211 struct message *m;
212 {
213         char *fromid, *toid, fbuf[32], tbuf[32];
214         unsigned char *f, *t, *iphdr;
215         int ftype, ttype;
216
217         fromid = m->from_if->id;
218         ftype = m->from_if->type;
219         f = (unsigned char *)&m->fip;
220         if(ftype == IF_TYPE_IPUDP)
221                 (void)sprintf(fbuf,"(%d.%d.%d.%d:%d)",f[0],f[1],f[2],f[3],ntohs(m->fport));
222         else if(ftype == IF_TYPE_IPIP)
223                 (void)sprintf(fbuf, "(%d.%d.%d.%d)", f[0], f[1], f[2], f[3]);
224         else fbuf[0] = '\0';
225
226         if (m->to_if) {
227                 toid = m->to_if->id;
228                 ttype = m->to_if->type;
229                 t = (unsigned char *)&m->tip;
230         } else {
231                 toid = "BitBucket";
232                 ttype = IF_TYPE_NONE;
233                 t = (unsigned char *)&m->tip;
234         }
235         if(ttype == IF_TYPE_IPUDP)
236                 (void)sprintf(tbuf,"(%d.%d.%d.%d:%d)",t[0],t[1],t[2],t[3],ntohs(m->tport));
237         else if(ttype == IF_TYPE_IPIP)
238                 (void)sprintf(tbuf, "(%d.%d.%d.%d)",t[0],t[1],t[2],t[3]);
239         else tbuf[0] = '\0';
240
241         iphdr = m->msg;
242
243         syslog(LOG_DEBUG,"%d.%d.%d.%d->%d.%d.%d.%d len %d [%s%s->%s%s]",
244                 iphdr[12], iphdr[13], iphdr[14], iphdr[15],
245                 iphdr[16], iphdr[17], iphdr[18], iphdr[19], 
246                 m->length, fromid, fbuf, toid, tbuf);
247 }
248
249 /*
250  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
251  * find a route for a message
252  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
253  */
254
255 static int
256 find_route(m)
257 struct message *m;
258 {
259         int i;
260         unsigned int d;
261
262         if(m==NULL) return -1;          /* major internal problem :-) */
263
264         if(m->length < 20){
265                 m->to_if = NULL;
266                 return 0;
267         }
268
269         (void)memcpy( (char *)&d, (char *)m->msg + 16, 4);
270
271         for(i=0;i<martian_count;i++){
272                 if(d == htonl(martians[i])){            /* Bad address! */
273                         m->from_if->martians_in++;
274                         m->to_if = NULL;
275                         return 0;
276                 }
277         }
278
279         for(i=0;i<rts_top;i++){
280                 if((rts[i].ipaddr & rts[i].mask) == (d & rts[i].mask)){
281                         m->to_if = rts[i].destif;
282                         m->tip = rts[i].destaddr;
283                         m->tport = rts[i].destport;
284                         rts[i].hits++;
285                         return 1;
286                 }
287         }
288         m->to_if = NULL;
289         return 0;
290 }
291
292 /*
293  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
294  * Send the statistics if it's time to do so...
295  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
296  */
297
298 void
299 send_stats(force)
300 int force;                      /* non-zero to force a stat print */
301 {
302         int i;
303         time_t now;
304         struct tm *t;
305         char cnow[32];
306
307         if(stat_interval==0) return;    /* no stat print at all? */
308
309         now = time(NULL);
310
311         if(force==0){                   /* if not being forced */
312                 if(stat_interval>0){            /* and the interval is > 0 */
313                         if(now < (last_send + stat_interval)) return;
314                 }
315         }
316
317         if(no_timestamp){
318                 cnow[0] = '\0';
319         } else {
320                 t = localtime(&now);
321                 (void)sprintf(cnow,"%2d/%2d/%2d %2d:%2d:%2d ",t->tm_mon + 1,
322                         t->tm_mday,t->tm_year,t->tm_hour,t->tm_min,t->tm_sec);
323         }
324
325         for(i=0;i<ifs_top;i++){
326                 if(ifs[i].type == IF_TYPE_NONE)continue;
327                 syslog(LOG_DEBUG,"%s%-4s in %4ld out %4ld baddr %ld loop %ld bogus %ld ovrn %ld\n",
328                         cnow, ifs[i].id, ifs[i].in, ifs[i].out,
329                         ifs[i].martians_in,ifs[i].looped_in,
330                         ifs[i].bogus_in, ifs[i].out_overruns);
331         }
332
333         last_send = now;
334 }