📄 server.c
字号:
/* get-next-event loop * 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: server.c,v 1.103 2004/11/30 02:28:07 mcr Exp $ */#include <stdio.h>#include <stdlib.h>#include <stddef.h>#include <string.h>#include <errno.h>#include <signal.h>#include <ctype.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/socket.h>#include <sys/un.h>#ifdef SOLARIS# include <sys/sockio.h> /* for Solaris 2.6: defines SIOCGIFCONF */#endif#include <netinet/in.h>#include <arpa/inet.h>#include <sys/time.h>#include <netdb.h>#include <unistd.h>#include <fcntl.h>#include <net/if.h>#include <sys/ioctl.h>#include <resolv.h>#include <arpa/nameser.h> /* missing from <resolv.h> on old systems */#include <sys/queue.h>#include <sys/resource.h>#include <sys/wait.h>#include <openswan.h>#include "constants.h"#include "defs.h"#include "state.h"#include "id.h"#include "x509.h"#include "pgp.h"#include "certs.h"#include "smartcard.h"#ifdef XAUTH_USEPAM#include <security/pam_appl.h>#endif#include "connections.h" /* needs id.h */#include "kernel.h" /* for no_klips; needs connections.h */#include "log.h"#include "server.h"#include "timer.h"#include "packet.h"#include "demux.h" /* needs packet.h */#include "rcv_whack.h"#include "rcv_info.h"#include "keys.h"#include "adns.h" /* needs <resolv.h> */#include "dnskey.h" /* needs keys.h and adns.h */#include "whack.h" /* for RC_LOG_SERIOUS */#include "pluto_crypt.h" /* cryptographic helper functions */#include <pfkeyv2.h>#include <pfkey.h>#include "kameipsec.h"#ifdef NAT_TRAVERSAL#include "nat_traversal.h"#endif/* * Server main loop and socket initialization routines. */static const int on = TRUE; /* by-reference parameter; constant, we hope */bool no_retransmits = FALSE;/* control (whack) socket */int ctl_fd = NULL_FD; /* file descriptor of control (whack) socket */struct sockaddr_un ctl_addr = { AF_UNIX, DEFAULT_CTLBASE CTL_SUFFIX };/* info (showpolicy) socket */int policy_fd = NULL_FD;struct sockaddr_un info_addr= { AF_UNIX, DEFAULT_CTLBASE INFO_SUFFIX };/* Initialize the control socket. * Note: this is called very early, so little infrastructure is available. * It is important that the socket is created before the original * Pluto process returns. */err_tinit_ctl_socket(void){ err_t failed = NULL; delete_ctl_socket(); /* preventative medicine */ ctl_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (ctl_fd == -1) failed = "create"; else if (fcntl(ctl_fd, F_SETFD, FD_CLOEXEC) == -1) failed = "fcntl FD+CLOEXEC"; else if (setsockopt(ctl_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) < 0) failed = "setsockopt"; else { /* to keep control socket secure, use umask */ mode_t ou = umask(~S_IRWXU); if (bind(ctl_fd, (struct sockaddr *)&ctl_addr , offsetof(struct sockaddr_un, sun_path) + strlen(ctl_addr.sun_path)) < 0) failed = "bind"; umask(ou); } /* 5 is a haphazardly chosen limit for the backlog. * Rumour has it that this is the max on BSD systems. */ if (failed == NULL && listen(ctl_fd, 5) < 0) failed = "listen() on"; return failed == NULL? NULL : builddiag("could not %s control socket: %d %s" , failed, errno, strerror(errno));}voiddelete_ctl_socket(void){ /* Is noting failure useful? Not when used as preventative medicine. */ unlink(ctl_addr.sun_path);}#ifdef IPSECPOLICY/* Initialize the info socket. */err_tinit_info_socket(void){ err_t failed = NULL; delete_info_socket(); /* preventative medicine */ info_fd = socket(AF_UNIX, SOCK_STREAM, 0); if (info_fd == -1) failed = "create"; else if (fcntl(info_fd, F_SETFD, FD_CLOEXEC) == -1) failed = "fcntl FD+CLOEXEC"; else if (setsockopt(info_fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&on, sizeof(on)) < 0) failed = "setsockopt"; else { /* this socket should be openable by all proceses */ mode_t ou = umask(0); if (bind(info_fd, (struct sockaddr *)&info_addr , offsetof(struct sockaddr_un, sun_path) + strlen(info_addr.sun_path)) < 0) failed = "bind"; umask(ou); } /* 64 might be big enough, and the system may limit us anyway. */ if (failed == NULL && listen(info_fd, 64) < 0) failed = "listen() on"; return failed == NULL? NULL : builddiag("could not %s info socket: %d %s" , failed, errno, strerror(errno));}voiddelete_info_socket(void){ unlink(info_addr.sun_path);}#endif /* IPSECPOLICY */bool listening = FALSE; /* should we pay attention to IKE messages? */struct iface *interfaces = NULL; /* public interfaces *//* Initialize the interface sockets. */static voidmark_ifaces_dead(void){ struct iface *p; for (p = interfaces; p != NULL; p = p->next) p->change = IFN_DELETE;}static voidfree_dead_ifaces(void){ struct iface *p; bool some_dead = FALSE , some_new = FALSE; for (p = interfaces; p != NULL; p = p->next) { if (p->change == IFN_DELETE) { openswan_log("shutting down interface %s/%s %s" , p->vname, p->rname, ip_str(&p->addr)); some_dead = TRUE; } else if (p->change == IFN_ADD) { some_new = TRUE; } } if (some_dead) { struct iface **pp; release_dead_interfaces(); for (pp = &interfaces; (p = *pp) != NULL; ) { if (p->change == IFN_DELETE) { *pp = p->next; /* advance *pp */ pfree(p->vname); pfree(p->rname); close(p->fd); pfree(p); } else { pp = &p->next; /* advance pp */ } } } /* this must be done after the release_dead_interfaces * in case some to the newly unoriented connections can * become oriented here. */ if (some_dead || some_new) check_orientations();}voidfree_ifaces(void){ mark_ifaces_dead(); free_dead_ifaces();}struct raw_iface { ip_address addr; char name[IFNAMSIZ + 20]; /* what would be a safe size? */ struct raw_iface *next;};/* Called to handle --interface <ifname> * Semantics: if specified, only these (real) interfaces are considered. */static const char *pluto_ifn[10];static int pluto_ifn_roof = 0;booluse_interface(const char *rifn){ if(pluto_ifn_inst[0]=='\0') { pluto_ifn_inst = clone_str(rifn, "genifn"); } if (pluto_ifn_roof >= (int)elemsof(pluto_ifn)) { return FALSE; } else { pluto_ifn[pluto_ifn_roof++] = rifn; return TRUE; }}#ifndef IPSECDEVPREFIX# define IPSECDEVPREFIX "ipsec"#endifstatic struct raw_iface *find_raw_ifaces4(void){ int j; /* index into buf */ struct ifconf ifconf; struct ifreq buf[300]; /* for list of interfaces -- arbitrary limit */ struct raw_iface *rifaces = NULL; int master_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); /* Get a UDP socket */ /* get list of interfaces with assigned IPv4 addresses from system */ if (master_sock == -1) exit_log_errno((e, "socket() failed in find_raw_ifaces4()")); if (setsockopt(master_sock, SOL_SOCKET, SO_REUSEADDR , (const void *)&on, sizeof(on)) < 0) exit_log_errno((e, "setsockopt() in find_raw_ifaces4()")); /* bind the socket */ { ip_address any; happy(anyaddr(AF_INET, &any)); setportof(htons(pluto_port), &any); if (bind(master_sock, sockaddrof(&any), sockaddrlenof(&any)) < 0) exit_log_errno((e, "bind() failed in find_raw_ifaces4()")); } /* Get local interfaces. See netdevice(7). */ ifconf.ifc_len = sizeof(buf); ifconf.ifc_buf = (void *) buf; zero(buf); if (ioctl(master_sock, SIOCGIFCONF, &ifconf) == -1) exit_log_errno((e, "ioctl(SIOCGIFCONF) in find_raw_ifaces4()")); /* Add an entry to rifaces for each interesting interface. */ for (j = 0; (j+1) * sizeof(*buf) <= (size_t)ifconf.ifc_len; j++) { struct raw_iface ri; const struct sockaddr_in *rs = (struct sockaddr_in *) &buf[j].ifr_addr; struct ifreq auxinfo; /* ignore all but AF_INET interfaces */ if (rs->sin_family != AF_INET) continue; /* not interesting */ /* build a NUL-terminated copy of the rname field */ memcpy(ri.name, buf[j].ifr_name, IFNAMSIZ); ri.name[IFNAMSIZ] = '\0'; /* ignore if our interface names were specified, and this isn't one */ if (pluto_ifn_roof != 0) { int i; for (i = 0; i != pluto_ifn_roof; i++) if (streq(ri.name, pluto_ifn[i])) break; if (i == pluto_ifn_roof) continue; /* not found -- skip */ } /* Find out stuff about this interface. See netdevice(7). */ zero(&auxinfo); /* paranoia */ memcpy(auxinfo.ifr_name, buf[j].ifr_name, IFNAMSIZ); if (ioctl(master_sock, SIOCGIFFLAGS, &auxinfo) == -1) exit_log_errno((e , "ioctl(SIOCGIFFLAGS) for %s in find_raw_ifaces4()" , ri.name)); if (!(auxinfo.ifr_flags & IFF_UP)) continue; /* ignore an interface that isn't UP */ /* ignore unconfigured interfaces */ if (rs->sin_addr.s_addr == 0) continue; happy(initaddr((const void *)&rs->sin_addr, sizeof(struct in_addr) , AF_INET, &ri.addr)); DBG(DBG_CONTROL, DBG_log("found %s with address %s" , ri.name, ip_str(&ri.addr))); ri.next = rifaces; rifaces = clone_thing(ri, "struct raw_iface"); } close(master_sock); return rifaces;}static struct raw_iface *find_raw_ifaces6(void){ /* Get list of interfaces with IPv6 addresses from system from /proc/net/if_inet6). * * Documentation of format? * RTFS: linux-2.2.16/net/ipv6/addrconf.c:iface_proc_info() * linux-2.4.9-13/net/ipv6/addrconf.c:iface_proc_info() * * Sample from Gerhard's laptop: * 00000000000000000000000000000001 01 80 10 80 lo * 30490009000000000000000000010002 02 40 00 80 ipsec0 * 30490009000000000000000000010002 07 40 00 80 eth0 * fe80000000000000025004fffefd5484 02 0a 20 80 ipsec0 * fe80000000000000025004fffefd5484 07 0a 20 80 eth0 * * Each line contains: * - IPv6 address: 16 bytes, in hex, no punctuation * - ifindex: 1 byte, in hex * - prefix_len: 1 byte, in hex * - scope (e.g. global, link local): 1 byte, in hex * - flags: 1 byte, in hex * - device name: string, followed by '\n' */ struct raw_iface *rifaces = NULL; static const char proc_name[] = "/proc/net/if_inet6"; FILE *proc_sock = fopen(proc_name, "r"); if (proc_sock == NULL) { DBG(DBG_CONTROL, DBG_log("could not open %s", proc_name)); } else { for (;;) { struct raw_iface ri; unsigned short xb[8]; /* IPv6 address as 8 16-bit chunks */ char sb[8*5]; /* IPv6 address as string-with-colons */ unsigned int if_idx; /* proc field, not used */ unsigned int plen; /* proc field, not used */ unsigned int scope; /* proc field, used to exclude link-local */ unsigned int dad_status; /* proc field, not used */ /* ??? I hate and distrust scanf -- DHR */ int r = fscanf(proc_sock , "%4hx%4hx%4hx%4hx%4hx%4hx%4hx%4hx" " %02x %02x %02x %02x %20s\n" , xb+0, xb+1, xb+2, xb+3, xb+4, xb+5, xb+6, xb+7 , &if_idx, &plen, &scope, &dad_status, ri.name); /* ??? we should diagnose any problems */ if (r != 13) break; /* ignore addresses with link local scope. * From linux-2.4.9-13/include/net/ipv6.h: * IPV6_ADDR_LINKLOCAL 0x0020U * IPV6_ADDR_SCOPE_MASK 0x00f0U */ if ((scope & 0x00f0U) == 0x0020U) continue; snprintf(sb, sizeof(sb) , "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" , xb[0], xb[1], xb[2], xb[3], xb[4], xb[5], xb[6], xb[7]); happy(ttoaddr(sb, 0, AF_INET6, &ri.addr)); if (!isunspecaddr(&ri.addr)) { DBG(DBG_CONTROL , DBG_log("found %s with address %s" , ri.name, sb)); ri.next = rifaces; rifaces = clone_thing(ri, "struct raw_iface"); } } fclose(proc_sock); } return rifaces;}static intcreate_socket(struct raw_iface *ifp, const char *v_name, int port){ int fd = socket(addrtypeof(&ifp->addr), SOCK_DGRAM, IPPROTO_UDP); int fcntl_flags; if (fd < 0) { log_errno((e, "socket() in process_raw_ifaces()")); return -1; } /* Set socket Nonblocking */ if ((fcntl_flags=fcntl(fd, F_GETFL)) >= 0) { if (!(fcntl_flags & O_NONBLOCK)) { fcntl_flags |= O_NONBLOCK; fcntl(fd, F_SETFL, fcntl_flags); } } if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) { log_errno((e, "fcntl(,, FD_CLOEXEC) in process_raw_ifaces()")); close(fd); return -1; } if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR , (const void *)&on, sizeof(on)) < 0) { log_errno((e, "setsockopt SO_REUSEADDR in process_raw_ifaces()")); close(fd); return -1; } /* To improve error reporting. See ip(7). */#if defined(IP_RECVERR) && defined(MSG_ERRQUEUE) if (setsockopt(fd, SOL_IP, IP_RECVERR , (const void *)&on, sizeof(on)) < 0) { log_errno((e, "setsockopt IP_RECVERR in process_raw_ifaces()")); close(fd); return -1; }#endif /* With IPv6, there is no fragmentation after * it leaves our interface. PMTU discovery * is mandatory but doesn't work well with IKE (why?). * So we must set the IPV6_USE_MIN_MTU option. * See draft-ietf-ipngwg-rfc2292bis-01.txt 11.1 */#ifdef IPV6_USE_MIN_MTU /* YUCK: not always defined */ if (addrtypeof(&ifp->addr) == AF_INET6 && setsockopt(fd, SOL_SOCKET, IPV6_USE_MIN_MTU , (const void *)&on, sizeof(on)) < 0) { log_errno((e, "setsockopt IPV6_USE_MIN_MTU in process_raw_ifaces()")); close(fd); return -1; }#endif#if defined(linux) && defined(KERNEL26_SUPPORT) if (!no_klips && kernel_ops->type == KERNEL_TYPE_LINUX) { struct sadb_x_policy policy; int level, opt; policy.sadb_x_policy_len = sizeof(policy) / IPSEC_PFKEYv2_ALIGN; policy.sadb_x_policy_exttype = SADB_X_EXT_POLICY; policy.sadb_x_policy_type = IPSEC_POLICY_BYPASS; policy.sadb_x_policy_dir = IPSEC_DIR_INBOUND; policy.sadb_x_policy_reserved = 0; policy.sadb_x_policy_id = 0; policy.sadb_x_policy_reserved2 = 0; if (addrtypeof(&ifp->addr) == AF_INET6) { level = IPPROTO_IPV6; opt = IPV6_IPSEC_POLICY; } else { level = IPPROTO_IP; opt = IP_IPSEC_POLICY; } if (setsockopt(fd, level, opt , &policy, sizeof(policy)) < 0) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -