1145519Sdarrenr/* $FreeBSD: stable/11/contrib/ipfilter/ipsend/ipsopt.c 369186 2021-01-31 04:32:46Z cy $ */ 2145510Sdarrenr 322514Sdarrenr/* 4255332Scy * Copyright (C) 2012 by Darren Reed. 522514Sdarrenr * 680486Sdarrenr * See the IPFILTER.LICENCE file for details on licencing. 7145510Sdarrenr * 822514Sdarrenr */ 9145510Sdarrenr#if !defined(lint) 10145510Sdarrenrstatic const char sccsid[] = "@(#)ipsopt.c 1.2 1/11/96 (C)1995 Darren Reed"; 11255332Scystatic const char rcsid[] = "@(#)$Id$"; 1292686Sdarrenr#endif 1392686Sdarrenr#include <sys/param.h> 1422514Sdarrenr#include <sys/types.h> 1522514Sdarrenr#include <sys/time.h> 1622514Sdarrenr#include <sys/socket.h> 1722514Sdarrenr#include <netinet/in.h> 1822514Sdarrenr#include <netinet/in_systm.h> 1922514Sdarrenr#include <netinet/ip.h> 20145510Sdarrenr#include <stdio.h> 21145510Sdarrenr#include <string.h> 22145510Sdarrenr#include <stdlib.h> 2331183Speter#include <netinet/ip_var.h> 2431183Speter#include <netinet/tcp.h> 2531183Speter#include <arpa/inet.h> 2631183Speter#include "ipsend.h" 2722514Sdarrenr 28145510Sdarrenr 29145510Sdarrenr#ifndef __P 30145510Sdarrenr# define __P(x) x 3124583Sdarrenr#endif 3224583Sdarrenr 3324583Sdarrenr 3422514Sdarrenrstruct ipopt_names ionames[] = { 3522514Sdarrenr { IPOPT_EOL, 0x01, 1, "eol" }, 3622514Sdarrenr { IPOPT_NOP, 0x02, 1, "nop" }, 3731183Speter { IPOPT_RR, 0x04, 3, "rr" }, /* 1 route */ 3822514Sdarrenr { IPOPT_TS, 0x08, 8, "ts" }, /* 1 TS */ 3922514Sdarrenr { IPOPT_SECURITY, 0x08, 11, "sec-level" }, 4022514Sdarrenr { IPOPT_LSRR, 0x10, 7, "lsrr" }, /* 1 route */ 4122514Sdarrenr { IPOPT_SATID, 0x20, 4, "satid" }, 4222514Sdarrenr { IPOPT_SSRR, 0x40, 7, "ssrr" }, /* 1 route */ 4322514Sdarrenr { 0, 0, 0, NULL } /* must be last */ 4422514Sdarrenr}; 4522514Sdarrenr 4622514Sdarrenrstruct ipopt_names secnames[] = { 4722514Sdarrenr { IPOPT_SECUR_UNCLASS, 0x0100, 0, "unclass" }, 4822514Sdarrenr { IPOPT_SECUR_CONFID, 0x0200, 0, "confid" }, 4922514Sdarrenr { IPOPT_SECUR_EFTO, 0x0400, 0, "efto" }, 5022514Sdarrenr { IPOPT_SECUR_MMMM, 0x0800, 0, "mmmm" }, 5122514Sdarrenr { IPOPT_SECUR_RESTR, 0x1000, 0, "restr" }, 5222514Sdarrenr { IPOPT_SECUR_SECRET, 0x2000, 0, "secret" }, 5322514Sdarrenr { IPOPT_SECUR_TOPSECRET, 0x4000,0, "topsecret" }, 5422514Sdarrenr { 0, 0, 0, NULL } /* must be last */ 5522514Sdarrenr}; 5622514Sdarrenr 5722514Sdarrenr 58145510Sdarrenru_short ipseclevel(slevel) 59255332Scy char *slevel; 6022514Sdarrenr{ 6122514Sdarrenr struct ipopt_names *so; 6222514Sdarrenr 6322514Sdarrenr for (so = secnames; so->on_name; so++) 6422514Sdarrenr if (!strcasecmp(slevel, so->on_name)) 6522514Sdarrenr break; 6622514Sdarrenr 6722514Sdarrenr if (!so->on_name) { 6822514Sdarrenr fprintf(stderr, "no such security level: %s\n", slevel); 6922514Sdarrenr return 0; 7022514Sdarrenr } 7122514Sdarrenr return so->on_value; 7222514Sdarrenr} 7322514Sdarrenr 7422514Sdarrenr 7531183Speterint addipopt(op, io, len, class) 76255332Scy char *op; 77255332Scy struct ipopt_names *io; 78255332Scy int len; 79255332Scy char *class; 8031183Speter{ 8131183Speter struct in_addr ipadr; 8231183Speter int olen = len, srr = 0; 8331183Speter u_short val; 8431183Speter u_char lvl; 8531183Speter char *s = op, *t; 8631183Speter 8731183Speter if ((len + io->on_siz) > 48) { 8831183Speter fprintf(stderr, "options too long\n"); 8931183Speter return 0; 9031183Speter } 9131183Speter len += io->on_siz; 9231183Speter *op++ = io->on_value; 9331183Speter if (io->on_siz > 1) { 9431183Speter /* 9531183Speter * Allow option to specify RR buffer length in bytes. 9631183Speter */ 9731183Speter if (io->on_value == IPOPT_RR) { 9831183Speter val = (class && *class) ? atoi(class) : 4; 9931183Speter *op++ = val + io->on_siz; 10031183Speter len += val; 10131183Speter } else 10231183Speter *op++ = io->on_siz; 103130887Sdarrenr if (io->on_value == IPOPT_TS) 104130887Sdarrenr *op++ = IPOPT_MINOFF + 1; 105130887Sdarrenr else 106130887Sdarrenr *op++ = IPOPT_MINOFF; 10731183Speter 10831183Speter while (class && *class) { 10931183Speter t = NULL; 11031183Speter switch (io->on_value) 11131183Speter { 11231183Speter case IPOPT_SECURITY : 113145510Sdarrenr lvl = ipseclevel(class); 11431183Speter *(op - 1) = lvl; 11531183Speter break; 11631183Speter case IPOPT_LSRR : 11731183Speter case IPOPT_SSRR : 11831183Speter if ((t = strchr(class, ','))) 11931183Speter *t = '\0'; 12031183Speter ipadr.s_addr = inet_addr(class); 12131183Speter srr++; 12231183Speter bcopy((char *)&ipadr, op, sizeof(ipadr)); 12331183Speter op += sizeof(ipadr); 12431183Speter break; 12531183Speter case IPOPT_SATID : 12631183Speter val = atoi(class); 12731183Speter bcopy((char *)&val, op, 2); 12831183Speter break; 12931183Speter } 13031183Speter 13131183Speter if (t) 13231183Speter *t++ = ','; 13331183Speter class = t; 13431183Speter } 13531183Speter if (srr) 13631183Speter s[IPOPT_OLEN] = IPOPT_MINOFF - 1 + 4 * srr; 13731183Speter if (io->on_value == IPOPT_RR) 13831183Speter op += val; 13931183Speter else 14031183Speter op += io->on_siz - 3; 14131183Speter } 14231183Speter return len - olen; 14331183Speter} 14431183Speter 14531183Speter 14631183Speteru_32_t buildopts(cp, op, len) 147255332Scy char *cp, *op; 148255332Scy int len; 14922514Sdarrenr{ 15022514Sdarrenr struct ipopt_names *io; 15131183Speter u_32_t msk = 0; 15222514Sdarrenr char *s, *t; 15331183Speter int inc, lastop = -1; 15422514Sdarrenr 15522514Sdarrenr for (s = strtok(cp, ","); s; s = strtok(NULL, ",")) { 15622514Sdarrenr if ((t = strchr(s, '='))) 15722514Sdarrenr *t++ = '\0'; 15822514Sdarrenr for (io = ionames; io->on_name; io++) { 15922514Sdarrenr if (strcasecmp(s, io->on_name) || (msk & io->on_bit)) 16022514Sdarrenr continue; 16131183Speter lastop = io->on_value; 16231183Speter if ((inc = addipopt(op, io, len, t))) { 16331183Speter op += inc; 16431183Speter len += inc; 16522514Sdarrenr } 16622514Sdarrenr msk |= io->on_bit; 16722514Sdarrenr break; 16822514Sdarrenr } 16922514Sdarrenr if (!io->on_name) { 17022514Sdarrenr fprintf(stderr, "unknown IP option name %s\n", s); 17122514Sdarrenr return 0; 17222514Sdarrenr } 17322514Sdarrenr } 17431183Speter 17531183Speter if (len & 3) { 17631183Speter while (len & 3) { 17731183Speter *op++ = ((len & 3) == 3) ? IPOPT_EOL : IPOPT_NOP; 17831183Speter len++; 17931183Speter } 18031183Speter } else { 18131183Speter if (lastop != IPOPT_EOL) { 18231183Speter if (lastop == IPOPT_NOP) 18331183Speter *(op - 1) = IPOPT_EOL; 18431183Speter else { 18531183Speter *op++ = IPOPT_NOP; 18631183Speter *op++ = IPOPT_NOP; 18731183Speter *op++ = IPOPT_NOP; 18831183Speter *op = IPOPT_EOL; 18931183Speter len += 4; 19031183Speter } 19131183Speter } 19231183Speter } 19322514Sdarrenr return len; 19422514Sdarrenr} 195