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