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