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