📄 klips.c
字号:
/* $OpenBSD: klips.c,v 1.3 2003/09/26 15:59:34 aaron Exp $ *//* * Copyright (c) 1999 Niklas Hallqvist. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *//* * This code was written under funding by Ericsson Radio Systems. */#include <asm/types.h>#include <sys/types.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/socket.h>#include <linux/sockios.h>#include <net/route.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <fcntl.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <unistd.h>#include <freeswan.h>#include <net/ipsec/radij.h>#include <net/ipsec/ipsec_encap.h>#include <net/ipsec/ipsec_netlink.h>#include <net/ipsec/ipsec_xform.h>#include <net/ipsec/ipsec_ipe4.h>#include <net/ipsec/ipsec_ah.h>#include <net/ipsec/ipsec_esp.h>#include "sysdep.h"#include "conf.h"#include "exchange.h"#include "hash.h"#include "ipsec.h"#include "ipsec_doi.h"#include "ipsec_num.h"#include "isakmp.h"#include "log.h"#include "klips.h"#include "sa.h"#include "timer.h"#include "transport.h"#define KLIPS_DEVICE "/dev/ipsec"#define PROC_ROUTE_FILE "/proc/net/route"#define PROC_ROUTE_FMT "%15s %127s %127s %X %d %d %d %127s %d %d %d\n"/* XXX Maybe these are available through some system-supplied define? */#define AH_NEW_XENCAP_LEN (3 * sizeof(u_short) + 2 * sizeof(u_char))#define ESP_NEW_XENCAP_LEN sizeof (struct espblkrply_edata)#define EMT_GRPSPIS_COMPLEN (sizeof (((struct encap_msghdr *)0)->em_rel[0]))/* How often should we check that connections we require to be up, are up? */#define KLIPS_CHECK_FREQ 60static int klips_socket;/* Open the KLIPS device. */intklips_open (){ int fd; fd = open (KLIPS_DEVICE, O_RDWR); if (fd == -1) { log_error ("klips_open: open (\"%s\", O_RDWR) failed", KLIPS_DEVICE); return -1; } klips_socket = fd; return fd;}/* Write a KLIPS request down to the kernel. */static intklips_write (struct encap_msghdr *em){ ssize_t n; em->em_magic = EM_MAGIC; em->em_version = 0; LOG_DBG_BUF ((LOG_SYSDEP, 30, "klips_write: em", (u_int8_t *)em, em->em_msglen)); n = write (klips_socket, em, em->em_msglen); if (n == -1) { log_error ("write (%d, ...) failed", klips_socket); return -1; } if ((size_t)n != em->em_msglen) { log_error ("write (%d, ...) returned prematurely", klips_socket); return -1; } return 0;}/* * Generate a SPI for protocol PROTO and the source/destination pair given by * SRC, SRCLEN, DST & DSTLEN. Stash the SPI size in SZ. */u_int8_t *klips_get_spi (size_t *sz, u_int8_t proto, struct sockaddr *src, struct sockaddr *dst, u_int32_t seq){ u_int8_t *spi; u_int32_t spinum; *sz = IPSEC_SPI_SIZE; spi = malloc (*sz); if (!spi) return 0; do spinum = sysdep_random (); while (spinum < IPSEC_SPI_LOW); spinum = htonl (spinum); memcpy (spi, &spinum, *sz); LOG_DBG_BUF ((LOG_SYSDEP, 50, "klips_get_spi: spi", spi, *sz)); return spi;}/* Group 2 SPIs in a chain. XXX Not fully implemented yet. */intklips_group_spis (struct sa *sa, struct proto *proto1, struct proto *proto2, int incoming){ struct encap_msghdr *emsg = 0; struct sockaddr *dst; emsg = calloc (1, EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN); if (!emsg) return -1; emsg->em_msglen = EMT_GRPSPIS_FLEN + 2 * EMT_GRPSPIS_COMPLEN; emsg->em_type = EMT_GRPSPIS; /* * XXX The code below is wrong if we are in tunnel mode. * The fix is to reorder stuff so the IP-in-IP SA will always come * upfront, and if there are two such, one is dropped. */ memcpy (&emsg->em_rel[0].emr_spi, proto1->spi[incoming], sizeof emsg->em_rel[0].emr_spi); memcpy (&emsg->em_rel[1].emr_spi, proto2->spi[incoming], sizeof emsg->em_rel[1].emr_spi); if (incoming) sa->transport->vtbl->get_src (sa->transport, &dst); else sa->transport->vtbl->get_dst (sa->transport, &dst); emsg->em_rel[0].emr_dst = emsg->em_rel[1].emr_dst = ((struct sockaddr_in *)dst)->sin_addr; /* XXX What if IPCOMP etc. comes along? */ emsg->em_rel[0].emr_proto = proto1->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; emsg->em_rel[1].emr_proto = proto2->proto == IPSEC_PROTO_IPSEC_ESP ? IPPROTO_ESP : IPPROTO_AH; if (klips_write (emsg)) goto cleanup; free (emsg); LOG_DBG ((LOG_SYSDEP, 50, "klips_group_spis: done")); return 0; cleanup: if (emsg) free (emsg); return -1;}/* Store/update a SPI with full information into the kernel. */intklips_set_spi (struct sa *sa, struct proto *proto, int incoming, struct sa *isakmp_sa){ struct encap_msghdr *emsg = 0; struct ipsec_proto *iproto = proto->data; struct sockaddr *dst, *src; int keylen, hashlen; size_t len; struct ipe4_xdata *ip4x; /* Actually works for all. */ struct espblkrply_edata *edx; /* Actually works for all. */ struct ahhmacmd5_edata *amx; switch (proto->proto) { case IPSEC_PROTO_IPSEC_ESP: keylen = ipsec_esp_enckeylength (proto); hashlen = ipsec_esp_authkeylength (proto); len = EMT_SETSPI_FLEN + ESP_NEW_XENCAP_LEN; emsg = calloc (1, len); if (!emsg) return -1; emsg->em_proto = IPPROTO_ESP; edx = (struct espblkrply_edata *)emsg->em_dat; /* Funny expression due to I just want one switch. */ switch (proto->id | (iproto->auth << 8)) { case IPSEC_ESP_3DES: emsg->em_alg = XF_ESP3DES; break; case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_MD5 << 8): emsg->em_alg = XF_ESP3DESMD596; break; case IPSEC_ESP_3DES | (IPSEC_AUTH_HMAC_SHA << 8): emsg->em_alg = XF_ESP3DESSHA196; break; default: LOG_DBG ((LOG_SYSDEP, 10, "klips_set_spi: Unsupported enc/auth alg negotiated")); return -1; } /* XXX What if we have a protocol requiring IV? */ edx->eme_ivlen = EMT_ESPDES_IV_SZ; edx->eme_klen = keylen; edx->ame_klen = hashlen;#if 0 /* I have reason to believe Shared-SADB won't work at all in KLIPS. */ edx->eme_ooowin = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window;#else edx->eme_ooowin = iproto->replay_window;#endif /* * XXX Pluto sets the unused by KLIPS flag EME_INITIATOR in * edx->eme_flags, if the party is the initiator. Should we too? */ edx->eme_flags = 0; memcpy (edx->eme_key, iproto->keymat[incoming], keylen); if (iproto->auth) memcpy (edx->ame_key, iproto->keymat[incoming] + keylen, hashlen); break; case IPSEC_PROTO_IPSEC_AH: hashlen = ipsec_ah_keylength (proto); len = EMT_SETSPI_FLEN + AH_NEW_XENCAP_LEN + hashlen; emsg = calloc (1, len); if (!emsg) return -1; emsg->em_proto = IPPROTO_AH; amx = (struct ahhmacmd5_edata *)emsg->em_dat; switch (proto->id) { case IPSEC_AH_MD5: emsg->em_alg = XF_AHHMACMD5; break; case IPSEC_AH_SHA: emsg->em_alg = XF_AHHMACSHA1; break; default: /* XXX Log? */ goto cleanup; } /* XXX Should we be able to send in different lengths here? */ amx->ame_alen = amx->ame_klen = hashlen;#if 0 /* I have reason to believe Shared-SADB won't work at all in KLIPS. */ amx->ame_ooowin = conf_get_str ("General", "Shared-SADB") ? 0 : iproto->replay_window;#else amx->ame_ooowin = iproto->replay_window;#endif amx->ame_replayp = amx->ame_ooowin > 0; memcpy (amx->ame_key, iproto->keymat[incoming], hashlen); break; default: /* XXX Log? */ goto cleanup; } emsg->em_msglen = len; emsg->em_type = EMT_SETSPI; memcpy (&emsg->em_spi, proto->spi[incoming], sizeof emsg->em_spi); emsg->em_flags = incoming ? EMT_INBOUND : 0; /* * XXX Addresses has to be thought through. Assumes IPv4. */ sa->transport->vtbl->get_dst (sa->transport, &dst); sa->transport->vtbl->get_src (sa->transport, &src); emsg->em_dst
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -