1 /* $FreeBSD$ */ 2 3 /* 4 * Copyright (C) 2012 by Darren Reed. 5 * 6 * See the IPFILTER.LICENCE file for details on licencing. 7 * 8 */ 9 #if !defined(lint) 10 static const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; 11 static const char rcsid[] = "@(#)$Id$"; 12 #endif 13 #include <sys/param.h> 14 #include <sys/types.h> 15 #include <sys/time.h> 16 #include <sys/socket.h> 17 #include <netinet/in.h> 18 #include <netinet/in_systm.h> 19 #include <netinet/ip.h> 20 #include <stdio.h> 21 #include <string.h> 22 #include <stdlib.h> 23 #include <netinet/ip_var.h> 24 #include <netinet/tcp.h> 25 #include <arpa/inet.h> 26 #include "ipsend.h" 27 28 29 #ifndef __P 30 # define __P(x) x 31 #endif 32 33 34 struct ipopt_names ionames[] = { 35 { IPOPT_EOL, 0x01, 1, "eol" }, 36 { IPOPT_NOP, 0x02, 1, "nop" }, 37 { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ 38 { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ 39 { IPOPT_SECURITY, 0x08, 11, "sec-level" }, 40 { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ 41 { IPOPT_SATID, 0x20, 4, "satid" }, 42 { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ 43 { 0, 0, 0, NULL } /* must be last */ 44 }; 45 46 struct ipopt_names secnames[] = { 47 { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, 48 { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, 49 { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, 50 { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, 51 { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, 52 { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, 53 { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, 54 { 0, 0, 0, NULL } /* must be last */ 55 }; 56 57 58 u_short ipseclevel(slevel) 59 char *slevel; 60 { 61 struct ipopt_names *so; 62 63 for (so = secnames; so->on_name; so++) 64 if (!strcasecmp(slevel, so->on_name)) 65 break; 66 67 if (!so->on_name) { 68 fprintf(stderr, "no such security level: %s\n", slevel); 69 return (0); 70 } 71 return (so->on_value); 72 } 73 74 75 int 76 addipopt(char *op, struct ipopt_names *io, int len, char *class) 77 { 78 struct in_addr ipadr; 79 int olen = len, srr = 0; 80 u_short val; 81 u_char lvl; 82 char *s = op, *t; 83 84 if ((len + io->on_siz) > 48) { 85 fprintf(stderr, "options too long\n"); 86 return (0); 87 } 88 len += io->on_siz; 89 *op++ = io->on_value; 90 if (io->on_siz > 1) { 91 /* 92 * Allow option to specify RR buffer length in bytes. 93 */ 94 if (io->on_value == IPOPT_RR) { 95 val = (class && *class) ? atoi(class) : 4; 96 *op++ = val + io->on_siz; 97 len += val; 98 } else 99 *op++ = io->on_siz; 100 if (io->on_value == IPOPT_TS) 101 *op++ = IPOPT_MINOFF + 1; 102 else 103 *op++ = IPOPT_MINOFF; 104 105 while (class && *class) { 106 t = NULL; 107 switch (io->on_value) 108 { 109 case IPOPT_SECURITY : 110 lvl = ipseclevel(class); 111 *(op - 1) = lvl; 112 break; 113 case IPOPT_LSRR : 114 case IPOPT_SSRR : 115 if ((t = strchr(class, ','))) 116 *t = '\0'; 117 ipadr.s_addr = inet_addr(class); 118 srr++; 119 bcopy((char *)&ipadr, op, sizeof(ipadr)); 120 op += sizeof(ipadr); 121 break; 122 case IPOPT_SATID : 123 val = atoi(class); 124 bcopy((char *)&val, op, 2); 125 break; 126 } 127 128 if (t) 129 *t++ = ','; 130 class = t; 131 } 132 if (srr) 133 s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; 134 if (io->on_value == IPOPT_RR) 135 op += val; 136 else 137 op += io->on_siz - 3; 138 } 139 return (len - olen); 140 } 141 142 143 u_32_t 144 buildopts(char *cp, char *op, int len) 145 char *cp, *op; 146 int len; 147 { 148 struct ipopt_names *io; 149 u_32_t msk = 0; 150 char *s, *t; 151 int inc, lastop = -1; 152 153 for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { 154 if ((t = strchr(s, '='))) 155 *t++ = '\0'; 156 for (io = ionames; io->on_name; io++) { 157 if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) 158 continue; 159 lastop = io->on_value; 160 if ((inc = addipopt(op, io, len, t))) { 161 op += inc; 162 len += inc; 163 } 164 msk |= io->on_bit; 165 break; 166 } 167 if (!io->on_name) { 168 fprintf(stderr, "unknown IP option name %s\n", s); 169 return (0); 170 } 171 } 172 173 if (len & 3) { 174 while (len & 3) { 175 *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; 176 len++; 177 } 178 } else { 179 if (lastop != IPOPT_EOL) { 180 if (lastop == IPOPT_NOP) 181 *(op - 1) = IPOPT_EOL; 182 else { 183 *op++ = IPOPT_NOP; 184 *op++ = IPOPT_NOP; 185 *op++ = IPOPT_NOP; 186 *op = IPOPT_EOL; 187 len += 4; 188 } 189 } 190 } 191 return (len); 192 } 193