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