xref: /freebsd/usr.sbin/ppp/ip.c (revision ce834215a70ff69e7e222827437116eee2f9ac6f)
1 /*
2  *		PPP IP Protocol Interface
3  *
4  *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5  *
6  *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the Internet Initiative Japan.  The name of the
14  * IIJ may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * $Id: ip.c,v 1.21 1997/06/09 03:27:23 brian Exp $
21  *
22  *	TODO:
23  *		o Return ICMP message for filterd packet
24  *		  and optionaly record it into log.
25  */
26 #include "fsm.h"
27 #include "lcpproto.h"
28 #include "hdlc.h"
29 #include <netinet/in_systm.h>
30 #include <netinet/ip.h>
31 #include <netinet/ip_icmp.h>
32 #include <netinet/udp.h>
33 #include <netinet/tcp.h>
34 #include <arpa/inet.h>
35 #include <alias.h>
36 #include "loadalias.h"
37 #include "vars.h"
38 #include "filter.h"
39 #include "mbuf.h"
40 #include "log.h"
41 
42 extern void SendPppFrame();
43 extern void LcpClose();
44 
45 static struct pppTimer IdleTimer;
46 
47 static void IdleTimeout()
48 {
49   LogPrintf(LogPHASE, "Idle timer expired.\n");
50   reconnect(RECON_FALSE);
51   LcpClose();
52 }
53 
54 /*
55  *  Start Idle timer. If timeout is reached, we call LcpClose() to
56  *  close LCP and link.
57  */
58 void
59 StartIdleTimer()
60 {
61   if (!(mode & (MODE_DEDICATED|MODE_DDIAL))) {
62     StopTimer(&IdleTimer);
63     IdleTimer.func = IdleTimeout;
64     IdleTimer.load = VarIdleTimeout * SECTICKS;
65     IdleTimer.state = TIMER_STOPPED;
66     StartTimer(&IdleTimer);
67   }
68 }
69 
70 void
71 UpdateIdleTimer()
72 {
73   if (IdleTimer.state == TIMER_RUNNING)
74     StartIdleTimer();
75 }
76 
77 void
78 StopIdleTimer()
79 {
80   StopTimer(&IdleTimer);
81 }
82 
83 /*
84  *  If any IP layer traffic is detected, refresh IdleTimer.
85  */
86 static void
87 RestartIdleTimer()
88 {
89   if (!(mode & (MODE_DEDICATED|MODE_DDIAL)) && ipKeepAlive ) {
90     StartTimer(&IdleTimer);
91     ipIdleSecs = 0;
92   }
93 }
94 
95 static u_short interactive_ports[32] = {
96   544, 513, 514,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,
97     0,   0,   0,   0,   0,  21,  22,  23,   0,   0,   0,   0,   0,   0,   0, 543,
98 };
99 
100 #define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
101 
102 static char *TcpFlags[] = {
103   "FIN", "SYN", "RST", "PSH", "ACK", "URG",
104 };
105 
106 static char *Direction[] = { "INP", "OUT", "OUT", "IN/OUT" };
107 static struct filterent *Filters[] = { ifilters, ofilters, dfilters, afilters };
108 
109 static int
110 PortMatch(op, pport, rport)
111 int op;
112 u_short pport, rport;
113 {
114   switch (op) {
115   case OP_EQ:
116     return(pport == rport);
117   case OP_GT:
118     return(pport > rport);
119   case OP_LT:
120     return(pport < rport);
121   default:
122     return(0);
123   }
124 }
125 
126 /*
127  *  Check a packet against with defined filters
128  */
129 static int
130 FilterCheck(pip, direction)
131 struct ip *pip;
132 int direction;
133 {
134   struct filterent *fp = Filters[direction];
135   int gotinfo, cproto, estab, n;
136   struct tcphdr *th;
137   struct udphdr *uh;
138   struct icmp *ih;
139   char *ptop;
140   u_short sport, dport;
141 
142   if (fp->action) {
143     cproto = gotinfo = estab = 0;
144     sport = dport = 0;
145     for (n = 0; n < MAXFILTERS; n++) {
146       if (fp->action) {
147          /* permit fragments on in and out filter */
148          if ((direction == FL_IN || direction == FL_OUT) &&
149              (ntohs(pip->ip_off) & IP_OFFMASK) != 0) {
150               return(A_PERMIT);
151          }
152         LogPrintf(LogDEBUG, "rule = %d\n", n);
153 	if ((pip->ip_src.s_addr & fp->smask.s_addr) == fp->saddr.s_addr
154 	    && (pip->ip_dst.s_addr & fp->dmask.s_addr) == fp->daddr.s_addr) {
155 	  if (fp->proto) {
156 	    if (!gotinfo) {
157 	      ptop = (char *)pip + (pip->ip_hl << 2);
158 
159 	      switch (pip->ip_p) {
160 	      case IPPROTO_ICMP:
161 		cproto = P_ICMP; ih = (struct icmp *)ptop;
162 		sport = ih->icmp_type; estab = 1;
163 		break;
164 	      case IPPROTO_UDP:
165 		cproto = P_UDP; uh = (struct udphdr *)ptop;
166 		sport = ntohs(uh->uh_sport); dport = ntohs(uh->uh_dport);
167 		estab = 1;
168 		break;
169 	      case IPPROTO_TCP:
170 		cproto = P_TCP; th = (struct tcphdr *)ptop;
171 		sport = ntohs(th->th_sport); dport = ntohs(th->th_dport);
172 		estab = (th->th_flags & TH_ACK);
173                 if (estab == 0)
174                   LogPrintf(LogDEBUG, "flag = %02x, sport = %d, dport = %d\n",
175                             th->th_flags, sport, dport);
176 		break;
177 	      default:
178 		return(A_DENY);	/* We'll block unknown type of packet */
179 	      }
180 	      gotinfo = 1;
181               LogPrintf(LogDEBUG, "dir = %d, proto = %d, srcop = %d,"
182                        " dstop = %d, estab = %d\n", direction, cproto,
183                        fp->opt.srcop, fp->opt.dstop, estab);
184 	    }
185 
186 	    LogPrintf(LogDEBUG, "check0: rule = %d, proto = %d, sport = %d,"
187                       " dport = %d\n", n, cproto, sport, dport);
188 	    LogPrintf(LogDEBUG, "check0: action = %d\n", fp->action);
189 
190 	    if (cproto == fp->proto) {
191 	      if ((fp->opt.srcop == OP_NONE ||
192 		  PortMatch(fp->opt.srcop, sport, fp->opt.srcport))
193 	       &&
194 		  (fp->opt.dstop == OP_NONE ||
195 		  PortMatch(fp->opt.dstop, dport, fp->opt.dstport))
196 	       &&
197 		  (fp->opt.estab == 0 || estab)) {
198 		return(fp->action);
199 	      }
200 	    }
201 	  } else {
202 	    /* Address is mached. Make a decision. */
203 	    LogPrintf(LogDEBUG, "check1: action = %d\n", fp->action);
204 	    return(fp->action);
205 	  }
206 	}
207       }
208       fp++;
209     }
210     return(A_DENY);	/* No rule is mached. Deny this packet */
211   }
212   return(A_PERMIT);	/* No rule is given. Permit this packet */
213 }
214 
215 static void
216 IcmpError(pip, code)
217 struct ip *pip;
218 int code;
219 {
220 #ifdef notdef
221   struct mbuf *bp;
222 
223   if (pip->ip_p != IPPROTO_ICMP) {
224     bp = mballoc(cnt, MB_IPIN);
225     bcopy(ptr, MBUF_CTOP(bp), cnt);
226     SendPppFrame(bp);
227     RestartIdleTimer();
228     ipOutOctets += cnt;
229   }
230 #endif
231 }
232 
233 /*
234  *  For debugging aid.
235  */
236 int
237 PacketCheck(cp, nb, direction)
238 char *cp;
239 int nb;
240 int direction;
241 {
242   struct ip *pip;
243   struct tcphdr *th;
244   struct udphdr *uh;
245   struct icmp *icmph;
246   char *ptop;
247   int mask, len, n;
248   int pri = PRI_NORMAL;
249   int logit, loglen;
250   static char logbuf[200];
251 
252   logit = LogIsKept(LogTCPIP);
253   loglen = 0;
254 
255   pip = (struct ip *)cp;
256 
257   if (logit && loglen < sizeof logbuf) {
258     snprintf(logbuf+loglen, sizeof logbuf - loglen, "%s ",
259              Direction[direction]);
260     loglen += strlen(logbuf+loglen);
261   }
262 
263   ptop = (cp + (pip->ip_hl << 2));
264 
265   switch (pip->ip_p) {
266   case IPPROTO_ICMP:
267     if (logit && loglen < sizeof logbuf) {
268       icmph = (struct icmp *)ptop;
269       snprintf(logbuf+loglen, sizeof logbuf - loglen,
270                "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
271       loglen += strlen(logbuf+loglen);
272       snprintf(logbuf+loglen, sizeof logbuf - loglen,
273                "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
274       loglen += strlen(logbuf+loglen);
275     }
276     break;
277   case IPPROTO_UDP:
278     if (logit && loglen < sizeof logbuf) {
279       uh = (struct udphdr *)ptop;
280       snprintf(logbuf+loglen, sizeof logbuf - loglen,
281                "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
282       loglen += strlen(logbuf+loglen);
283       snprintf(logbuf+loglen, sizeof logbuf - loglen,
284                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
285       loglen += strlen(logbuf+loglen);
286     }
287     break;
288   case IPPROTO_TCP:
289     th = (struct tcphdr *)ptop;
290     if (pip->ip_tos == IPTOS_LOWDELAY)
291       pri = PRI_FAST;
292     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
293       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
294 	 pri = PRI_FAST;
295     }
296 
297     if (logit && loglen < sizeof logbuf) {
298       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
299       snprintf(logbuf+loglen, sizeof logbuf - loglen,
300                "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
301       loglen += strlen(logbuf+loglen);
302       snprintf(logbuf+loglen, sizeof logbuf - loglen,
303                "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
304       loglen += strlen(logbuf+loglen);
305       n = 0;
306       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
307 	if (th->th_flags & mask) {
308           snprintf(logbuf+loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
309           loglen += strlen(logbuf+loglen);
310         }
311 	n++;
312       }
313       snprintf(logbuf+loglen, sizeof logbuf - loglen,
314                "  seq:%x  ack:%x (%d/%d)",
315                ntohl(th->th_seq), ntohl(th->th_ack), len, nb);
316       loglen += strlen(logbuf+loglen);
317       if ((th->th_flags & TH_SYN) && nb > 40) {
318         u_short *sp;
319 
320 	ptop += 20;
321 	sp = (u_short *)ptop;
322 	if (ntohs(sp[0]) == 0x0204) {
323           snprintf(logbuf+loglen, sizeof logbuf - loglen,
324 	           " MSS = %d", ntohs(sp[1]));
325           loglen += strlen(logbuf+loglen);
326         }
327       }
328     }
329     break;
330   }
331 
332   if (logit)
333     LogPrintf(LogTCPIP, "%s\n", logbuf);
334 
335   if ((FilterCheck(pip, direction) & A_DENY)) {
336     LogPrintf(LogDEBUG, "blocked.\n");
337     if (direction == 0) IcmpError(pip, pri);
338     return(-1);
339   } else {
340     if ( FilterCheck(pip, FL_KEEP ) & A_DENY ) {  /* Check Keep Alive filter */
341 	ipKeepAlive = FALSE;
342     } else {
343 	ipKeepAlive = TRUE;
344     }
345     return(pri);
346   }
347 }
348 
349 void
350 IpInput(bp)
351 struct mbuf *bp;		/* IN: Pointer to IP pakcet */
352 {
353   u_char *cp;
354   struct mbuf *wp;
355   int nb, nw;
356   u_char tunbuff[MAX_MRU];
357 
358   cp = tunbuff;
359   nb = 0;
360   for (wp = bp; wp; wp = wp->next) {		/* Copy to contiguous region */
361     bcopy(MBUF_CTOP(wp), cp, wp->cnt);
362     cp += wp->cnt;
363     nb += wp->cnt;
364   }
365 
366   if (mode & MODE_ALIAS) {
367     int iresult;
368     char *fptr;
369 
370     iresult = VarPacketAliasIn(tunbuff, sizeof tunbuff);
371     nb = ntohs(((struct ip *) tunbuff)->ip_len);
372 
373     if (nb > MAX_MRU) {
374       LogPrintf(LogERROR, "IpInput: Problem with IP header length\n");
375       pfree(bp);
376       return;
377     }
378 
379     if (iresult == PKT_ALIAS_OK
380      || iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
381       if ( PacketCheck(tunbuff, nb, FL_IN ) < 0) {
382           pfree(bp);
383           return;
384       }
385 
386       ipInOctets += nb;
387 
388       nb = ntohs(((struct ip *) tunbuff)->ip_len);
389       nw = write(tun_out, tunbuff, nb);
390       if (nw != nb)
391         LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
392 
393       if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
394         while ((fptr = VarGetNextFragmentPtr(tunbuff)) != NULL) {
395           VarFragmentAliasIn(tunbuff, fptr);
396           nb = ntohs(((struct ip *) fptr)->ip_len);
397           nw = write(tun_out, fptr, nb);
398           if (nw != nb)
399             LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
400           free(fptr);
401         }
402       }
403     }
404     else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
405       nb = ntohs(((struct ip *) tunbuff)->ip_len);
406       fptr = malloc(nb);
407       if (fptr == NULL)
408         LogPrintf(LogALERT, "IpInput: Cannot allocate memory for fragment\n");
409       else {
410         memcpy(fptr, tunbuff, nb);
411         VarSaveFragmentPtr(fptr);
412       }
413     }
414   }
415   else
416   { /* no aliasing */
417     if ( PacketCheck(tunbuff, nb, FL_IN ) < 0)
418     {
419       pfree(bp);
420       return;
421     }
422 
423     ipInOctets += nb;
424     nw = write(tun_out, tunbuff, nb);
425     if (nw != nb)
426       LogPrintf(LogERROR, "IpInput: wrote %d, got %d\n", nb, nw);
427   }
428   pfree(bp);
429 
430   RestartIdleTimer();
431 }
432 
433 static struct mqueue IpOutputQueues[PRI_FAST+1];
434 
435 void
436 IpEnqueue(pri, ptr, count)
437 int pri;
438 char *ptr;
439 int count;
440 {
441   struct mbuf *bp;
442 
443   bp = mballoc(count, MB_IPQ);
444   bcopy(ptr, MBUF_CTOP(bp), count);
445   Enqueue(&IpOutputQueues[pri], bp);
446 }
447 
448 int
449 IsIpEnqueued()
450 {
451   struct mqueue *queue;
452   int    exist = FALSE;
453   for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
454      if ( queue->qlen > 0 ) {
455        exist = TRUE;
456        break;
457      }
458   }
459   return( exist );
460 }
461 
462 void
463 IpStartOutput()
464 {
465   struct mqueue *queue;
466   struct mbuf *bp;
467   int cnt;
468 
469   if (IpcpFsm.state != ST_OPENED)
470     return;
471   for (queue = &IpOutputQueues[PRI_FAST]; queue >= IpOutputQueues; queue--) {
472     if (queue->top) {
473       bp = Dequeue(queue);
474       if (bp) {
475 	cnt = plength(bp);
476 	SendPppFrame(bp);
477 	RestartIdleTimer();
478 	ipOutOctets += cnt;
479 	break;
480        }
481     }
482   }
483 }
484