kernel.c
来自「ipsec vpn」· C语言 代码 · 共 2,050 行 · 第 1/5 页
C
2,050 行
/* routines that interface with the kernel's IPsec mechanism * Copyright (C) 1997 Angelos D. Keromytis. * Copyright (C) 1998-2002 D. Hugh Redelmeier. * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * * RCSID $Id: kernel.c,v 1.232.2.1 2005/10/21 02:50:46 ken Exp $ */#include <stddef.h>#include <string.h>#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <wait.h>#include <unistd.h>#include <fcntl.h>#include <sys/utsname.h>#include <sys/queue.h>#include <sys/stat.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <openswan.h>#include <openswan/ipsec_policy.h>#ifdef KLIPS#include <signal.h>#include <sys/time.h> /* for select(2) */#include <sys/types.h> /* for select(2) */#include <pfkeyv2.h>#include <pfkey.h>#include "kameipsec.h"#endif /* KLIPS */#include "constants.h"#include "oswlog.h"#include "defs.h"#include "rnd.h"#include "id.h"#include "connections.h" /* needs id.h */#include "state.h"#include "timer.h"#include "kernel.h"#include "kernel_netlink.h"#include "kernel_pfkey.h"#include "kernel_noklips.h"#include "packet.h"#include "x509.h"#include "log.h"#include "server.h"#include "whack.h" /* for RC_LOG_SERIOUS */#include "keys.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#ifdef NAT_TRAVERSAL#include "packet.h" /* for pb_stream in nat_traversal.h */#include "nat_traversal.h"#endifbool can_do_IPcomp = TRUE; /* can system actually perform IPCOMP? *//* test if the routes required for two different connections agree * It is assumed that the destination subnets agree; we are only * testing that the interfaces and nexthops match. */#define routes_agree(c, d) ((c)->interface->ip_dev == (d)->interface->ip_dev \ && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop))/* bare (connectionless) shunt (eroute) table * * Bare shunts are those that don't "belong" to a connection. * This happens because some %trapped traffic hasn't yet or cannot be * assigned to a connection. The usual reason is that we cannot discover * the peer SG. Another is that even when the peer has been discovered, * it may be that no connection matches all the particulars. * We record them so that, with scanning, we can discover * which %holds are news and which others should expire. */#define SHUNT_SCAN_INTERVAL (60 * 2) /* time between scans of eroutes *//* SHUNT_PATIENCE only has resolution down to a multiple of the sample rate, * SHUNT_SCAN_INTERVAL. * By making SHUNT_PATIENCE an odd multiple of half of SHUNT_SCAN_INTERVAL, * we minimize the effects of jitter. */#define SHUNT_PATIENCE (SHUNT_SCAN_INTERVAL * 15 / 2) /* inactivity timeout */struct bare_shunt { policy_prio_t policy_prio; ip_subnet ours; ip_subnet his; ip_said said; int transport_proto; unsigned long count; time_t last_activity; char *why; struct bare_shunt *next;};static struct bare_shunt *bare_shunts = NULL;#ifdef DEBUGstatic voidDBG_bare_shunt(const char *op, const struct bare_shunt *bs){ DBG(DBG_KLIPS, { int ourport = ntohs(portof(&(bs)->ours.addr)); int hisport = ntohs(portof(&(bs)->his.addr)); char ourst[SUBNETTOT_BUF]; char hist[SUBNETTOT_BUF]; char sat[SATOT_BUF]; char prio[POLICY_PRIO_BUF]; subnettot(&(bs)->ours, 0, ourst, sizeof(ourst)); subnettot(&(bs)->his, 0, hist, sizeof(hist)); satot(&(bs)->said, 0, sat, sizeof(sat)); fmt_policy_prio(bs->policy_prio, prio); DBG_log("%s bare shunt %p %s:%d -%d-> %s:%d => %s %s %s" , op, (const void *)(bs), ourst, ourport, (bs)->transport_proto, hist, hisport , sat, prio, (bs)->why); });}#else /* !DEBUG */#define DBG_bare_shunt(op, bs) {}#endif /* !DEBUG *//* The orphaned_holds table records %holds for which we * scan_proc_shunts found no representation of in any connection. * The corresponding ACQUIRE message might have been lost. */struct eroute_info *orphaned_holds = NULL;/* forward declaration */static bool shunt_eroute(struct connection *c , struct spd_route *sr , enum routing_t rt_kind , unsigned int op, const char *opname);static void set_text_said(char *text_said , const ip_address *dst , ipsec_spi_t spi , int proto);static const struct pfkey_proto_info narrow_proto_info[2] = { { proto: IPPROTO_ESP, encapsulation: ENCAPSULATION_MODE_TRANSPORT, reqid: 0 }, { proto: 0, encapsulation: 0, reqid: 0 }};static const struct pfkey_proto_info broad_proto_info[2] = { { proto: IPPROTO_ESP, encapsulation: ENCAPSULATION_MODE_TUNNEL, reqid: 0 }, { proto: 0, encapsulation: 0, reqid: 0 }};voidrecord_and_initiate_opportunistic(const ip_subnet *ours , const ip_subnet *his , int transport_proto , const char *why){ passert(samesubnettype(ours, his)); /* Add to bare shunt list. * We need to do this because the shunt was installed by KLIPS * which can't do this itself. */ { struct bare_shunt *bs = alloc_thing(struct bare_shunt, "bare shunt"); bs->why = clone_str(why, "story for bare shunt"); bs->ours = *ours; bs->his = *his; bs->transport_proto = transport_proto; bs->policy_prio = BOTTOM_PRIO; bs->said.proto = SA_INT; bs->said.spi = htonl(SPI_HOLD); bs->said.dst = *aftoinfo(subnettypeof(ours))->any; bs->count = 0; bs->last_activity = now(); bs->next = bare_shunts; bare_shunts = bs; DBG_bare_shunt("add", bs); } /* actually initiate opportunism */ { ip_address src, dst; networkof(ours, &src); networkof(his, &dst); initiate_opportunistic(&src, &dst, transport_proto, TRUE, NULL_FD, "acquire"); } /* * if present, remove from orphaned_holds list. * NOTE: we do this last in case ours or his is a pointer into a member. */ { struct eroute_info **pp, *p; for (pp = &orphaned_holds; (p = *pp) != NULL; pp = &p->next) { if (samesubnet(ours, &p->ours) && samesubnet(his, &p->his) && transport_proto == p->transport_proto && portof(&ours->addr) == portof(&p->ours.addr) && portof(&his->addr) == portof(&p->his.addr)) { *pp = p->next; pfree(p); break; } } }}static unsigned get_proto_reqid(unsigned base, int proto){ switch (proto) { default: case IPPROTO_COMP: base++; /* fall through */ case IPPROTO_ESP: base++; /* fall through */ case IPPROTO_AH: break; } return base;}/* Generate Unique SPI numbers. * * The specs say that the number must not be less than IPSEC_DOI_SPI_MIN. * Pluto generates numbers not less than IPSEC_DOI_SPI_OUR_MIN, * reserving numbers in between for manual keying (but we cannot so * restrict numbers generated by our peer). * XXX This should be replaced by a call to the kernel when * XXX we get an API. * The returned SPI is in network byte order. * We use a random number as the initial SPI so that there is * a good chance that different Pluto instances will choose * different SPIs. This is good for two reasons. * - the keying material for the initiator and responder only * differs if the SPIs differ. * - if Pluto is restarted, it would otherwise recycle the SPI * numbers and confuse everything. When the kernel generates * SPIs, this will no longer matter. * We then allocate numbers sequentially. Thus we don't have to * check if the number was previously used (assuming that no * SPI lives longer than 4G of its successors). */ipsec_spi_tget_ipsec_spi(ipsec_spi_t avoid, int proto, struct spd_route *sr, bool tunnel){ static ipsec_spi_t spi = 0; /* host order, so not returned directly! */ char text_said[SATOT_BUF]; set_text_said(text_said, &sr->this.host_addr, 0, proto); if (kernel_ops->get_spi) return kernel_ops->get_spi(&sr->that.host_addr , &sr->this.host_addr, proto, tunnel , get_proto_reqid(sr->reqid, proto) , IPSEC_DOI_SPI_OUR_MIN, 0xffffffff , text_said); spi++; while (spi < IPSEC_DOI_SPI_OUR_MIN || spi == ntohl(avoid)) get_rnd_bytes((u_char *)&spi, sizeof(spi)); DBG(DBG_CONTROL, { ipsec_spi_t spi_net = htonl(spi); DBG_dump("generate SPI:", (u_char *)&spi_net, sizeof(spi_net)); }); return htonl(spi);}/* Generate Unique CPI numbers. * The result is returned as an SPI (4 bytes) in network order! * The real bits are in the nework-low-order 2 bytes. * Modelled on get_ipsec_spi, but range is more limited: * 256-61439. * If we can't find one easily, return 0 (a bad SPI, * no matter what order) indicating failure. */ipsec_spi_tget_my_cpi(struct spd_route *sr, bool tunnel){ static cpi_t first_busy_cpi = 0, latest_cpi; char text_said[SATOT_BUF]; set_text_said(text_said, &sr->this.host_addr, 0, IPPROTO_COMP); if (kernel_ops->get_spi) return kernel_ops->get_spi(&sr->that.host_addr , &sr->this.host_addr, IPPROTO_COMP, tunnel , get_proto_reqid(sr->reqid, IPPROTO_COMP) , IPCOMP_FIRST_NEGOTIATED, IPCOMP_LAST_NEGOTIATED , text_said); while (!(IPCOMP_FIRST_NEGOTIATED <= first_busy_cpi && first_busy_cpi < IPCOMP_LAST_NEGOTIATED)) { get_rnd_bytes((u_char *)&first_busy_cpi, sizeof(first_busy_cpi)); latest_cpi = first_busy_cpi; } latest_cpi++; if (latest_cpi == first_busy_cpi) find_my_cpi_gap(&latest_cpi, &first_busy_cpi); if (latest_cpi > IPCOMP_LAST_NEGOTIATED) latest_cpi = IPCOMP_FIRST_NEGOTIATED; return htonl((ipsec_spi_t)latest_cpi);}static booldo_command(struct connection *c, struct spd_route *sr, const char *verb, struct state *st){ const char *verb_suffix; /* figure out which verb suffix applies for logging purposes */ { const char *hs, *cs; switch (addrtypeof(&sr->this.host_addr)) { case AF_INET: hs = "-host"; cs = "-client"; break; case AF_INET6: hs = "-host-v6"; cs = "-client-v6"; break; default: loglog(RC_LOG_SERIOUS, "unknown address family"); return FALSE; } verb_suffix = subnetisaddr(&sr->this.client, &sr->this.host_addr) ? hs : cs; } DBG(DBG_CONTROL, DBG_log("command executing %s%s" , verb, verb_suffix)); if(kernel_ops->docommand != NULL) { return (*kernel_ops->docommand)(c,sr, verb, st); } else { DBG(DBG_CONTROL, DBG_log("no do_command for method %s", kernel_ops->opname)); } return TRUE;}/* Check that we can route (and eroute). Diagnose if we cannot. */enum routability { route_impossible = 0, route_easy = 1, route_nearconflict = 2, route_farconflict = 3};static enum routabilitycould_route(struct connection *c)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?