📄 sysdep_linux.c
字号:
/* * routines that are Linux specific * * Copyright (C) 2005 Michael Richardson <mcr@xelerance.com> * 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: sysdep_linux.c,v 1.2 2005/07/19 20:34:15 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>#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"/* 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"#endifbooldo_command_linux(struct connection *c, struct spd_route *sr , const char *verb, struct state *st){ char cmd[1536]; /* arbitrary limit on shell command length */ const char *verb_suffix; /* figure out which verb suffix applies */ { 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; } /* form the command string */ { char nexthop_str[sizeof("PLUTO_NEXT_HOP='' ")+ADDRTOT_BUF], me_str[ADDRTOT_BUF], myid_str[IDTOA_BUF], srcip_str[ADDRTOT_BUF+sizeof("PLUTO_MY_SOURCEIP=")+4], myclient_str[SUBNETTOT_BUF], myclientnet_str[ADDRTOT_BUF], myclientmask_str[ADDRTOT_BUF], peer_str[ADDRTOT_BUF], peerid_str[IDTOA_BUF], peerclient_str[SUBNETTOT_BUF], peerclientnet_str[ADDRTOT_BUF], peerclientmask_str[ADDRTOT_BUF], secure_myid_str[IDTOA_BUF] = "", secure_peerid_str[IDTOA_BUF] = "", secure_peerca_str[IDTOA_BUF] = "", secure_xauth_username_str[IDTOA_BUF] = ""; ip_address ta; nexthop_str[0]='\0'; if(addrbytesptr(&sr->this.host_nexthop, NULL) && !isanyaddr(&sr->this.host_nexthop)) { char *n; strcpy(nexthop_str, "PLUTO_NEXT_HOP='"); n = nexthop_str + strlen(nexthop_str); addrtot(&sr->this.host_nexthop, 0, n, sizeof(nexthop_str)-strlen(nexthop_str)); strncat(nexthop_str, "' ", sizeof(nexthop_str)); } addrtot(&sr->this.host_addr, 0, me_str, sizeof(me_str)); idtoa(&sr->this.id, myid_str, sizeof(myid_str)); escape_metachar(myid_str, secure_myid_str, sizeof(secure_myid_str)); subnettot(&sr->this.client, 0, myclient_str, sizeof(myclientnet_str)); networkof(&sr->this.client, &ta); addrtot(&ta, 0, myclientnet_str, sizeof(myclientnet_str)); maskof(&sr->this.client, &ta); addrtot(&ta, 0, myclientmask_str, sizeof(myclientmask_str)); addrtot(&sr->that.host_addr, 0, peer_str, sizeof(peer_str)); idtoa(&sr->that.id, peerid_str, sizeof(peerid_str)); escape_metachar(peerid_str, secure_peerid_str, sizeof(secure_peerid_str)); subnettot(&sr->that.client, 0, peerclient_str, sizeof(peerclientnet_str)); networkof(&sr->that.client, &ta); addrtot(&ta, 0, peerclientnet_str, sizeof(peerclientnet_str)); maskof(&sr->that.client, &ta); addrtot(&ta, 0, peerclientmask_str, sizeof(peerclientmask_str)); secure_xauth_username_str[0]='\0'; if (st != NULL && st->st_xauth_username) { size_t len; strcpy(secure_xauth_username_str, "PLUTO_XAUTH_USERNAME='"); len = strlen(secure_xauth_username_str); remove_metachar(st->st_xauth_username ,secure_xauth_username_str+len ,sizeof(secure_xauth_username_str)-(len+2)); strncat(secure_xauth_username_str, "'", sizeof(secure_xauth_username_str)-1); } srcip_str[0]='\0'; if(addrbytesptr(&sr->this.host_srcip, NULL) != 0 && !isanyaddr(&sr->this.host_srcip)) { char *p; int l; strncat(srcip_str, "PLUTO_MY_SOURCEIP=", sizeof(srcip_str)); strncat(srcip_str, "'", sizeof(srcip_str)); l = strlen(srcip_str); p = srcip_str + l; addrtot(&sr->this.host_srcip, 0, p, sizeof(srcip_str)); strncat(srcip_str, "'", sizeof(srcip_str)); } { struct pubkey_list *p; char peerca_str[IDTOA_BUF]; for (p = pubkeys; p != NULL; p = p->next) { struct pubkey *key = p->key; int pathlen; if (key->alg == PUBKEY_ALG_RSA && same_id(&sr->that.id, &key->id) && trusted_ca(key->issuer, sr->that.ca, &pathlen)) { dntoa_or_null(peerca_str, IDTOA_BUF, key->issuer, ""); escape_metachar(peerca_str, secure_peerca_str, sizeof(secure_peerca_str)); break; } } } if (-1 == snprintf(cmd, sizeof(cmd) , "2>&1 " /* capture stderr along with stdout */ "PLUTO_VERSION='1.1' " /* change VERSION when interface spec changes */ "PLUTO_VERB='%s%s' " "PLUTO_CONNECTION='%s' " "%s" /* possible PLUTO_NEXT_HOP */ "PLUTO_INTERFACE='%s' " "PLUTO_ME='%s' " "PLUTO_MY_ID='%s' " "PLUTO_MY_CLIENT='%s' " "PLUTO_MY_CLIENT_NET='%s' " "PLUTO_MY_CLIENT_MASK='%s' " "PLUTO_MY_PORT='%u' " "PLUTO_MY_PROTOCOL='%u' " "PLUTO_PEER='%s' " "PLUTO_PEER_ID='%s' " "PLUTO_PEER_CLIENT='%s' " "PLUTO_PEER_CLIENT_NET='%s' " "PLUTO_PEER_CLIENT_MASK='%s' " "PLUTO_PEER_PORT='%u' " "PLUTO_PEER_PROTOCOL='%u' " "PLUTO_PEER_CA='%s' " "PLUTO_CONN_POLICY='%s' " "%s " "%s " /* PLUTO_MY_SRCIP */ "%s" /* actual script */ , verb, verb_suffix , c->name , nexthop_str , c->interface->ip_dev->id_vname , me_str , secure_myid_str , myclient_str , myclientnet_str , myclientmask_str , sr->this.port , sr->this.protocol , peer_str , secure_peerid_str , peerclient_str , peerclientnet_str , peerclientmask_str , sr->that.port , sr->that.protocol , secure_peerca_str , prettypolicy(c->policy) , secure_xauth_username_str , srcip_str , sr->this.updown == NULL? DEFAULT_UPDOWN : sr->this.updown)) { loglog(RC_LOG_SERIOUS, "%s%s command too long!", verb, verb_suffix); return FALSE; } } DBG(DBG_CONTROL, DBG_log("executing %s%s: %s" , verb, verb_suffix, cmd)); { /* invoke the script, catching stderr and stdout * It may be of concern that some file descriptors will * be inherited. For the ones under our control, we * have done fcntl(fd, F_SETFD, FD_CLOEXEC) to prevent this. * Any used by library routines (perhaps the resolver or syslog) * will remain. */ __sighandler_t savesig; FILE *f; savesig = signal(SIGCHLD, SIG_DFL); f = popen(cmd, "r"); if (f == NULL) { loglog(RC_LOG_SERIOUS, "unable to popen %s%s command", verb, verb_suffix); signal(SIGCHLD, savesig); return FALSE; } /* log any output */ for (;;) { /* if response doesn't fit in this buffer, it will be folded */ char resp[256]; if (fgets(resp, sizeof(resp), f) == NULL) { if (ferror(f)) { log_errno((e, "fgets failed on output of %s%s command" , verb, verb_suffix)); signal(SIGCHLD, savesig); return FALSE; } else { passert(feof(f)); break; } } else { char *e = resp + strlen(resp); if (e > resp && e[-1] == '\n') e[-1] = '\0'; /* trim trailing '\n' */ openswan_log("%s%s output: %s", verb, verb_suffix, resp); } } /* report on and react to return code */ { int r = pclose(f); signal(SIGCHLD, savesig); if (r == -1) { log_errno((e, "pclose failed for %s%s command" , verb, verb_suffix)); return FALSE; } else if (WIFEXITED(r)) { if (WEXITSTATUS(r) != 0) { loglog(RC_LOG_SERIOUS, "%s%s command exited with status %d" , verb, verb_suffix, WEXITSTATUS(r)); return FALSE; } } else if (WIFSIGNALED(r)) { loglog(RC_LOG_SERIOUS, "%s%s command exited with signal %d" , verb, verb_suffix, WTERMSIG(r)); return FALSE; } else { loglog(RC_LOG_SERIOUS, "%s%s command exited with unknown status %d" , verb, verb_suffix, r); return FALSE; } } } return TRUE;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -