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