xref: /freebsd/usr.sbin/ppp/ip.c (revision 2da199da53835ee2d9228a60717fd2d0fccf9e50)
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.54 1998/11/10 00:32:39 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 #ifdef __OpenBSD__
28 #include <sys/socket.h>
29 #endif
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 <sys/un.h>
38 
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44 
45 #ifndef NOALIAS
46 #ifdef __OpenBSD__
47 #include "alias.h"
48 #else
49 #include <alias.h>
50 #endif
51 #endif
52 #include "mbuf.h"
53 #include "log.h"
54 #include "defs.h"
55 #include "timer.h"
56 #include "fsm.h"
57 #include "lqr.h"
58 #include "hdlc.h"
59 #include "throughput.h"
60 #include "iplist.h"
61 #include "slcompress.h"
62 #include "ipcp.h"
63 #include "filter.h"
64 #include "descriptor.h"
65 #include "lcp.h"
66 #include "ccp.h"
67 #include "link.h"
68 #include "mp.h"
69 #ifndef NORADIUS
70 #include "radius.h"
71 #endif
72 #include "bundle.h"
73 #include "vjcomp.h"
74 #include "tun.h"
75 #include "ip.h"
76 
77 static const u_short interactive_ports[32] = {
78   544, 513, 514, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
79   0, 0, 0, 0, 0, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 543,
80 };
81 
82 #define	INTERACTIVE(p)	(interactive_ports[(p) & 0x1F] == (p))
83 
84 static const char *TcpFlags[] = { "FIN", "SYN", "RST", "PSH", "ACK", "URG" };
85 
86 static int
87 PortMatch(int op, u_short pport, u_short rport)
88 {
89   switch (op) {
90     case OP_EQ:
91     return (pport == rport);
92   case OP_GT:
93     return (pport > rport);
94   case OP_LT:
95     return (pport < rport);
96   default:
97     return (0);
98   }
99 }
100 
101 /*
102  *  Check a packet against with defined filters
103  */
104 static int
105 FilterCheck(struct ip *pip, struct filter *filter)
106 {
107   int gotinfo, cproto, estab, syn, finrst, n, len, didname;
108   struct tcphdr *th;
109   struct udphdr *uh;
110   struct icmp *ih;
111   char *ptop;
112   u_short sport, dport;
113   struct filterent *fp = filter->rule;
114   char dbuff[100];
115 
116   if (fp->action) {
117     cproto = gotinfo = estab = syn = finrst = didname = 0;
118     sport = dport = 0;
119     for (n = 0; n < MAXFILTERS; n++) {
120       if (fp->action) {
121 	/* permit fragments on in and out filter */
122         if (filter->fragok && (ntohs(pip->ip_off) & IP_OFFMASK) != 0)
123 	  return (A_PERMIT);
124 
125         if (!didname)
126           log_Printf(LogDEBUG, "%s filter:\n", filter->name);
127         didname = 1;
128 
129 	if ((pip->ip_src.s_addr & fp->smask.s_addr) ==
130 	    (fp->saddr.s_addr & fp->smask.s_addr) &&
131 	    (pip->ip_dst.s_addr & fp->dmask.s_addr) ==
132 	    (fp->daddr.s_addr & fp->dmask.s_addr)) {
133 	  if (fp->proto) {
134 	    if (!gotinfo) {
135 	      ptop = (char *) pip + (pip->ip_hl << 2);
136 
137 	      switch (pip->ip_p) {
138 	      case IPPROTO_ICMP:
139 		cproto = P_ICMP;
140 		ih = (struct icmp *) ptop;
141 		sport = ih->icmp_type;
142 		estab = syn = finrst = -1;
143                 if (log_IsKept(LogDEBUG))
144 		  snprintf(dbuff, sizeof dbuff, "sport = %d", sport);
145 		break;
146 	      case IPPROTO_UDP:
147 	      case IPPROTO_IGMP:
148 	      case IPPROTO_IPIP:
149 		cproto = P_UDP;
150 		uh = (struct udphdr *) ptop;
151 		sport = ntohs(uh->uh_sport);
152 		dport = ntohs(uh->uh_dport);
153 		estab = syn = finrst = -1;
154                 if (log_IsKept(LogDEBUG))
155 		  snprintf(dbuff, sizeof dbuff, "sport = %d, dport = %d",
156                            sport, dport);
157 		break;
158 	      case IPPROTO_TCP:
159 		cproto = P_TCP;
160 		th = (struct tcphdr *) ptop;
161 		sport = ntohs(th->th_sport);
162 		dport = ntohs(th->th_dport);
163 		estab = (th->th_flags & TH_ACK);
164 		syn = (th->th_flags & TH_SYN);
165 		finrst = (th->th_flags & (TH_FIN|TH_RST));
166                 if (log_IsKept(LogDEBUG)) {
167                   if (!estab)
168 		    snprintf(dbuff, sizeof dbuff,
169                              "flags = %02x, sport = %d, dport = %d",
170                              th->th_flags, sport, dport);
171                   else
172                     *dbuff = '\0';
173                 }
174 		break;
175 	      default:
176 		return (A_DENY);       /* We'll block unknown type of packet */
177 	      }
178               if (log_IsKept(LogDEBUG)) {
179                 if (estab != -1) {
180                   len = strlen(dbuff);
181                   snprintf(dbuff + len, sizeof dbuff - len,
182                            ", estab = %d, syn = %d, finrst = %d",
183                            estab, syn, finrst);
184                 }
185 	        log_Printf(LogDEBUG, " Filter: proto = %s, %s\n",
186                           filter_Proto2Nam(cproto), dbuff);
187               }
188 	      gotinfo = 1;
189 	    }
190             if (log_IsKept(LogDEBUG)) {
191 	      if (fp->opt.srcop != OP_NONE) {
192                 snprintf(dbuff, sizeof dbuff, ", src %s %d",
193                          filter_Op2Nam(fp->opt.srcop), fp->opt.srcport);
194                 len = strlen(dbuff);
195               } else
196                 len = 0;
197 	      if (fp->opt.dstop != OP_NONE) {
198                 snprintf(dbuff + len, sizeof dbuff - len,
199                          ", dst %s %d", filter_Op2Nam(fp->opt.dstop),
200                          fp->opt.dstport);
201               } else if (!len)
202                 *dbuff = '\0';
203 
204 	      log_Printf(LogDEBUG, "  rule = %d: Address match, "
205                         "check against proto %s%s, action = %s\n",
206                         n, filter_Proto2Nam(fp->proto),
207                         dbuff, filter_Action2Nam(fp->action));
208             }
209 
210 	    if (cproto == fp->proto) {
211 	      if ((fp->opt.srcop == OP_NONE ||
212 		   PortMatch(fp->opt.srcop, sport, fp->opt.srcport)) &&
213 		  (fp->opt.dstop == OP_NONE ||
214 		   PortMatch(fp->opt.dstop, dport, fp->opt.dstport)) &&
215 		  (fp->opt.estab == 0 || estab) &&
216 		  (fp->opt.syn == 0 || syn) &&
217 		  (fp->opt.finrst == 0 || finrst)) {
218 		return (fp->action);
219 	      }
220 	    }
221 	  } else {
222 	    /* Address is mached. Make a decision. */
223 	    log_Printf(LogDEBUG, "  rule = %d: Address match, action = %s\n", n,
224                       filter_Action2Nam(fp->action));
225 	    return (fp->action);
226 	  }
227 	} else
228 	  log_Printf(LogDEBUG, "  rule = %d: Address mismatch\n", n);
229       }
230       fp++;
231     }
232     return (A_DENY);		/* No rule is mached. Deny this packet */
233   }
234   return (A_PERMIT);		/* No rule is given. Permit this packet */
235 }
236 
237 #ifdef notdef
238 static void
239 IcmpError(struct ip * pip, int code)
240 {
241   struct mbuf *bp;
242 
243   if (pip->ip_p != IPPROTO_ICMP) {
244     bp = mbuf_Alloc(cnt, MB_IPIN);
245     memcpy(MBUF_CTOP(bp), ptr, cnt);
246     vj_SendFrame(bp);
247     ipcp_AddOutOctets(cnt);
248   }
249 }
250 #endif
251 
252 /*
253  *  For debugging aid.
254  */
255 int
256 PacketCheck(struct bundle *bundle, char *cp, int nb, struct filter *filter)
257 {
258   struct ip *pip;
259   struct tcphdr *th;
260   struct udphdr *uh;
261   struct icmp *icmph;
262   char *ptop;
263   int mask, len, n;
264   int pri = PRI_NORMAL;
265   int logit, loglen;
266   char logbuf[200];
267 
268   logit = log_IsKept(LogTCPIP) && filter->logok;
269   loglen = 0;
270 
271   pip = (struct ip *) cp;
272 
273   if (logit && loglen < sizeof logbuf) {
274     snprintf(logbuf + loglen, sizeof logbuf - loglen, "%s ", filter->name);
275     loglen += strlen(logbuf + loglen);
276   }
277   ptop = (cp + (pip->ip_hl << 2));
278 
279   switch (pip->ip_p) {
280   case IPPROTO_ICMP:
281     if (logit && loglen < sizeof logbuf) {
282       icmph = (struct icmp *) ptop;
283       snprintf(logbuf + loglen, sizeof logbuf - loglen,
284 	     "ICMP: %s:%d ---> ", inet_ntoa(pip->ip_src), icmph->icmp_type);
285       loglen += strlen(logbuf + loglen);
286       snprintf(logbuf + loglen, sizeof logbuf - loglen,
287 	       "%s:%d", inet_ntoa(pip->ip_dst), icmph->icmp_type);
288       loglen += strlen(logbuf + loglen);
289     }
290     break;
291   case IPPROTO_UDP:
292     if (logit && loglen < sizeof logbuf) {
293       uh = (struct udphdr *) ptop;
294       snprintf(logbuf + loglen, sizeof logbuf - loglen,
295 	   "UDP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
296       loglen += strlen(logbuf + loglen);
297       snprintf(logbuf + loglen, sizeof logbuf - loglen,
298 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
299       loglen += strlen(logbuf + loglen);
300     }
301     break;
302   case IPPROTO_IPIP:
303     if (logit && loglen < sizeof logbuf) {
304       uh = (struct udphdr *) ptop;
305       snprintf(logbuf + loglen, sizeof logbuf - loglen,
306 	   "IPIP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
307       loglen += strlen(logbuf + loglen);
308       snprintf(logbuf + loglen, sizeof logbuf - loglen,
309 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
310       loglen += strlen(logbuf + loglen);
311     }
312     break;
313   case IPPROTO_IGMP:
314     if (logit && loglen < sizeof logbuf) {
315       uh = (struct udphdr *) ptop;
316       snprintf(logbuf + loglen, sizeof logbuf - loglen,
317 	   "IGMP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(uh->uh_sport));
318       loglen += strlen(logbuf + loglen);
319       snprintf(logbuf + loglen, sizeof logbuf - loglen,
320 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(uh->uh_dport));
321       loglen += strlen(logbuf + loglen);
322     }
323     break;
324   case IPPROTO_TCP:
325     th = (struct tcphdr *) ptop;
326     if (pip->ip_tos == IPTOS_LOWDELAY)
327       pri = PRI_FAST;
328     else if ((ntohs(pip->ip_off) & IP_OFFMASK) == 0) {
329       if (INTERACTIVE(ntohs(th->th_sport)) || INTERACTIVE(ntohs(th->th_dport)))
330 	pri = PRI_FAST;
331     }
332     if (logit && loglen < sizeof logbuf) {
333       len = ntohs(pip->ip_len) - (pip->ip_hl << 2) - (th->th_off << 2);
334       snprintf(logbuf + loglen, sizeof logbuf - loglen,
335 	   "TCP: %s:%d ---> ", inet_ntoa(pip->ip_src), ntohs(th->th_sport));
336       loglen += strlen(logbuf + loglen);
337       snprintf(logbuf + loglen, sizeof logbuf - loglen,
338 	       "%s:%d", inet_ntoa(pip->ip_dst), ntohs(th->th_dport));
339       loglen += strlen(logbuf + loglen);
340       n = 0;
341       for (mask = TH_FIN; mask != 0x40; mask <<= 1) {
342 	if (th->th_flags & mask) {
343 	  snprintf(logbuf + loglen, sizeof logbuf - loglen, " %s", TcpFlags[n]);
344 	  loglen += strlen(logbuf + loglen);
345 	}
346 	n++;
347       }
348       snprintf(logbuf + loglen, sizeof logbuf - loglen,
349 	       "  seq:%lx  ack:%lx (%d/%d)",
350 	       (u_long)ntohl(th->th_seq), (u_long)ntohl(th->th_ack), len, nb);
351       loglen += strlen(logbuf + loglen);
352       if ((th->th_flags & TH_SYN) && nb > 40) {
353 	u_short *sp;
354 
355 	ptop += 20;
356 	sp = (u_short *) ptop;
357 	if (ntohs(sp[0]) == 0x0204) {
358 	  snprintf(logbuf + loglen, sizeof logbuf - loglen,
359 		   " MSS = %d", ntohs(sp[1]));
360 	  loglen += strlen(logbuf + loglen);
361 	}
362       }
363     }
364     break;
365   }
366 
367   if ((FilterCheck(pip, filter) & A_DENY)) {
368     if (logit)
369       log_Printf(LogTCPIP, "%s - BLOCKED\n", logbuf);
370 #ifdef notdef
371     if (direction == 0)
372       IcmpError(pip, pri);
373 #endif
374     return (-1);
375   } else {
376     /* Check Keep Alive filter */
377     if (logit) {
378       if (FilterCheck(pip, &bundle->filter.alive) & A_DENY)
379         log_Printf(LogTCPIP, "%s - NO KEEPALIVE\n", logbuf);
380       else
381         log_Printf(LogTCPIP, "%s\n", logbuf);
382     }
383     return (pri);
384   }
385 }
386 
387 void
388 ip_Input(struct bundle *bundle, struct mbuf * bp)
389 {
390   u_char *cp;
391   struct mbuf *wp;
392   int nb, nw;
393   struct tun_data tun;
394   struct ip *pip = (struct ip *)tun.data;
395 #ifndef NOALIAS
396   struct ip *piip = (struct ip *)((char *)pip + (pip->ip_hl << 2));
397 #endif
398 
399   tun_fill_header(tun, AF_INET);
400   cp = tun.data;
401   nb = 0;
402   for (wp = bp; wp; wp = wp->next) {	/* Copy to contiguous region */
403     if (sizeof tun.data - (cp - tun.data) < wp->cnt) {
404       log_Printf(LogWARN, "ip_Input: Packet too large (%d) - dropped\n",
405                 mbuf_Length(bp));
406       mbuf_Free(bp);
407       return;
408     }
409     memcpy(cp, MBUF_CTOP(wp), wp->cnt);
410     cp += wp->cnt;
411     nb += wp->cnt;
412   }
413 
414 #ifndef NOALIAS
415   if (bundle->AliasEnabled && pip->ip_p != IPPROTO_IGMP &&
416       (pip->ip_p != IPPROTO_IPIP || !IN_CLASSD(ntohl(piip->ip_dst.s_addr)))) {
417     struct tun_data *frag;
418     int iresult;
419     char *fptr;
420 
421     iresult = PacketAliasIn(tun.data, sizeof tun.data);
422     nb = ntohs(((struct ip *) tun.data)->ip_len);
423 
424     if (nb > MAX_MRU) {
425       log_Printf(LogWARN, "ip_Input: Problem with IP header length\n");
426       mbuf_Free(bp);
427       return;
428     }
429     if (iresult == PKT_ALIAS_OK
430 	|| iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
431       if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
432 	mbuf_Free(bp);
433 	return;
434       }
435 
436       if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
437         bundle_StartIdleTimer(bundle);
438 
439       ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
440 
441       nb = ntohs(((struct ip *) tun.data)->ip_len);
442       nb += sizeof tun - sizeof tun.data;
443       nw = write(bundle->dev.fd, &tun, nb);
444       if (nw != nb) {
445         if (nw == -1)
446 	  log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
447                     strerror(errno));
448         else
449 	  log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
450       }
451 
452       if (iresult == PKT_ALIAS_FOUND_HEADER_FRAGMENT) {
453 	while ((fptr = PacketAliasGetFragment(tun.data)) != NULL) {
454 	  PacketAliasFragmentIn(tun.data, fptr);
455 	  nb = ntohs(((struct ip *) fptr)->ip_len);
456           frag = (struct tun_data *)
457 	    ((char *)fptr - sizeof tun + sizeof tun.data);
458           nb += sizeof tun - sizeof tun.data;
459 	  nw = write(bundle->dev.fd, frag, nb);
460 	  if (nw != nb) {
461             if (nw == -1)
462 	      log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb,
463                         strerror(errno));
464             else
465 	      log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
466           }
467 	  free(frag);
468 	}
469       }
470     } else if (iresult == PKT_ALIAS_UNRESOLVED_FRAGMENT) {
471       nb = ntohs(((struct ip *) tun.data)->ip_len);
472       nb += sizeof tun - sizeof tun.data;
473       frag = (struct tun_data *)malloc(nb);
474       if (frag == NULL)
475 	log_Printf(LogALERT, "ip_Input: Cannot allocate memory for fragment\n");
476       else {
477         tun_fill_header(*frag, AF_INET);
478 	memcpy(frag->data, tun.data, nb - sizeof tun + sizeof tun.data);
479 	PacketAliasSaveFragment(frag->data);
480       }
481     }
482   } else
483 #endif /* #ifndef NOALIAS */
484   {			/* no aliasing */
485     if (PacketCheck(bundle, tun.data, nb, &bundle->filter.in) < 0) {
486       mbuf_Free(bp);
487       return;
488     }
489 
490     if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
491       bundle_StartIdleTimer(bundle);
492 
493     ipcp_AddInOctets(&bundle->ncp.ipcp, nb);
494 
495     nb += sizeof tun - sizeof tun.data;
496     nw = write(bundle->dev.fd, &tun, nb);
497     if (nw != nb) {
498       if (nw == -1)
499 	log_Printf(LogERROR, "ip_Input: wrote %d, got %s\n", nb, strerror(errno));
500       else
501         log_Printf(LogERROR, "ip_Input: wrote %d, got %d\n", nb, nw);
502     }
503   }
504   mbuf_Free(bp);
505 }
506 
507 void
508 ip_Enqueue(struct ipcp *ipcp, int pri, char *ptr, int count)
509 {
510   struct mbuf *bp;
511 
512   if (pri < 0 || pri > sizeof ipcp->Queue / sizeof ipcp->Queue[0])
513     log_Printf(LogERROR, "Can't store in ip queue %d\n", pri);
514   else {
515     bp = mbuf_Alloc(count, MB_IPQ);
516     memcpy(MBUF_CTOP(bp), ptr, count);
517     mbuf_Enqueue(&ipcp->Queue[pri], bp);
518   }
519 }
520 
521 void
522 ip_DeleteQueue(struct ipcp *ipcp)
523 {
524   struct mqueue *queue;
525 
526   for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
527     while (queue->top)
528       mbuf_Free(mbuf_Dequeue(queue));
529 }
530 
531 int
532 ip_QueueLen(struct ipcp *ipcp)
533 {
534   struct mqueue *queue;
535   int result = 0;
536 
537   for (queue = ipcp->Queue; queue < ipcp->Queue + PRI_MAX; queue++)
538     result += queue->qlen;
539 
540   return result;
541 }
542 
543 int
544 ip_FlushPacket(struct link *l, struct bundle *bundle)
545 {
546   struct ipcp *ipcp = &bundle->ncp.ipcp;
547   struct mqueue *queue;
548   struct mbuf *bp;
549   int cnt;
550 
551   if (ipcp->fsm.state != ST_OPENED)
552     return 0;
553 
554   for (queue = &ipcp->Queue[PRI_FAST]; queue >= ipcp->Queue; queue--)
555     if (queue->top) {
556       bp = mbuf_Dequeue(queue);
557       if (bp) {
558         struct ip *pip = (struct ip *)MBUF_CTOP(bp);
559 
560 	cnt = mbuf_Length(bp);
561         if (!(FilterCheck(pip, &bundle->filter.alive) & A_DENY))
562           bundle_StartIdleTimer(bundle);
563 	vj_SendFrame(l, bp, bundle);
564         ipcp_AddOutOctets(ipcp, cnt);
565 	return 1;
566       }
567     }
568 
569   return 0;
570 }
571