📄 kernel.c
字号:
/* 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.215 2004/12/09 18:13:29 mcr 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/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"#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? *//* How far can IPsec messages arrive out of order before the anti-replay * logic loses track and swats them? 64 is the best KLIPS can do. */#define REPLAY_WINDOW 64/* 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 == (d)->interface \ && sameaddr(&(c)->spd.this.host_nexthop, &(d)->spd.this.host_nexthop))#ifndef KLIPSbool no_klips = TRUE; /* don't actually use KLIPS */#else /* !KLIPS *//* 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);bool no_klips = FALSE; /* don't actually use KLIPS */static const struct pfkey_proto_info null_proto_info[2] = { { proto: IPPROTO_ESP, encapsulation: ENCAPSULATION_MODE_TRANSPORT, 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; } } }}#endif /* KLIPS */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);}/* invoke the updown script to do the routing and firewall commands required * * The user-specified updown script is run. Parameters are fed to it in * the form of environment variables. All such environment variables * have names starting with "PLUTO_". * * The operation to be performed is specified by PLUTO_VERB. This * verb has a suffix "-host" if the client on this end is just the * host; otherwise the suffix is "-client". If the address family * of the host is IPv6, an extra suffix of "-v6" is added. * * "prepare-host" and "prepare-client" are used to delete a route * that may exist (due to forces outside of Pluto). It is used to * prepare for pluto creating a route. * * "route-host" and "route-client" are used to install a route. * Since routing is based only on destination, the PLUTO_MY_CLIENT_* * values are probably of no use (using them may signify a bug). * * "unroute-host" and "unroute-client" are used to delete a route. * Since routing is based only on destination, the PLUTO_MY_CLIENT_* * values are probably of no use (using them may signify a bug). * * "up-host" and "up-client" are run when an eroute is added (not replaced). * They are useful for adjusting a firewall: usually for adding a rule * to let processed packets flow between clients. Note that only * one eroute may exist for a pair of client subnets but inbound * IPsec SAs may persist without an eroute. * * "down-host" and "down-client" are run when an eroute is deleted. * They are useful for adjusting a firewall. */#ifndef DEFAULT_UPDOWN# define DEFAULT_UPDOWN "ipsec _updown"#endifstatic booldo_command(struct connection *c, struct spd_route *sr, const char *verb){ char cmd[1536]; /* arbitrary limit on shell command length */ const char *verb_suffix;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -