diff --git a/distrib/sets/lists/base/shl.elf b/distrib/sets/lists/base/shl.elf index 6a91593aa398..4827378701fb 100644 --- a/distrib/sets/lists/base/shl.elf +++ b/distrib/sets/lists/base/shl.elf @@ -1,4 +1,4 @@ -# $NetBSD: shl.elf,v 1.14 1999/11/23 11:20:29 blymn Exp $ +# $NetBSD: shl.elf,v 1.15 2000/01/31 14:15:34 itojun Exp $ ./usr/lib/libamu.so.1 ./usr/lib/libbfd.so.3 ./usr/lib/libbz2.so.0 @@ -8,7 +8,7 @@ ./usr/lib/libedit.so.2 ./usr/lib/libg2c.so.0 ./usr/lib/libgnumalloc.so.0 -./usr/lib/libipsec.so.0 +./usr/lib/libipsec.so.1 ./usr/lib/libkvm.so.5 ./usr/lib/libm.so.0 ./usr/lib/libmenu.so.0 diff --git a/distrib/sets/lists/base/shl.mi b/distrib/sets/lists/base/shl.mi index 5dec029b7b1d..68b1fa2fb26b 100644 --- a/distrib/sets/lists/base/shl.mi +++ b/distrib/sets/lists/base/shl.mi @@ -1,4 +1,4 @@ -# $NetBSD: shl.mi,v 1.52 2000/01/28 17:40:41 itojun Exp $ +# $NetBSD: shl.mi,v 1.53 2000/01/31 14:15:34 itojun Exp $ ./usr/lib/libamu.so.1.1 ./usr/lib/libbfd.so.3.0 ./usr/lib/libbz2.so.0.0 @@ -8,7 +8,7 @@ ./usr/lib/libedit.so.2.3 ./usr/lib/libg2c.so.0.0 ./usr/lib/libgnumalloc.so.0.0 -./usr/lib/libipsec.so.0.0 +./usr/lib/libipsec.so.1.0 ./usr/lib/libkvm.so.5.0 ./usr/lib/libm.so.0.1 ./usr/lib/libmenu.so.0.1 diff --git a/lib/libipsec/Makefile b/lib/libipsec/Makefile index 2edf0d056c89..6d68b0b6438a 100644 --- a/lib/libipsec/Makefile +++ b/lib/libipsec/Makefile @@ -1,17 +1,24 @@ -# $NetBSD: Makefile,v 1.2 1999/07/03 06:59:28 itojun Exp $ +# $NetBSD: Makefile,v 1.3 2000/01/31 14:15:30 itojun Exp $ LIB= ipsec -#CFLAGS+=-g -CPPFLAGS+=-DIPSEC_DEBUG -CPPFLAGS+=-DIPSEC -CPPFLAGS+=-DINET6 +CFLAGS+=-g +CPPFLAGS+=-DIPSEC_DEBUG -DIPSEC -DINET6 -I. -DYY_NO_UNPUT .PATH: ${.CURDIR}/../../sys/netkey SRCS= pfkey.c pfkey_dump.c -SRCS+= ipsec_policy.c ipsec_strerror.c key_debug.c +SRCS+= ipsec_strerror.c policy_parse.y policy_token.l +SRCS+= ipsec_get_policylen.c ipsec_dump_policy.c +SRCS+= key_debug.c +LPREFIX+=__libyy +YPREFIX+=__libyy +YHEADER=1 + +#LFLAGS+= -olex.yy.c MAN= ipsec_set_policy.3 ipsec_strerror.3 MLINKS+=ipsec_set_policy.3 ipsec_get_policylen.3 \ ipsec_set_policy.3 ipsec_dump_policy.3 +CLEANFILES+= y.tab.h + .include diff --git a/lib/libipsec/ipsec_policy.c b/lib/libipsec/ipsec_policy.c deleted file mode 100644 index 0b114308a49d..000000000000 --- a/lib/libipsec/ipsec_policy.c +++ /dev/null @@ -1,667 +0,0 @@ -/* $NetBSD: ipsec_policy.c,v 1.3 1999/07/04 01:36:12 itojun Exp $ */ - -/* - * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. - * 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. - * 3. Neither the name of the project nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``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 PROJECT OR CONTRIBUTORS 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. - */ - -#if 0 -static char *rcsid = "@(#) ipsec_policy.c KAME Revision: 1.1.4.8"; -#else -#include -#ifndef lint -__RCSID("$NetBSD: ipsec_policy.c,v 1.3 1999/07/04 01:36:12 itojun Exp $"); -#endif -#endif - -/* - * The following requests are accepted: - * protocol parsed as protocol/default/ - * protocol/level/proxy - * protocol/ parsed as protocol/default/ - * protocol/level parsed as protocol/level/ - * protocol/level/ parsed as protocol/level/ - * protocol/proxy parsed as protocol/default/proxy - * protocol//proxy parsed as protocol/default/proxy - * protocol// parsed as protocol/default/ - * You can concatenate these requests with either ' ' or '\n'. - */ - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "ipsec_strerror.h" - -/* order must be the same */ -static char *tokens[] = { - "discard", "none", "ipsec", "entrust", "bypass", - "esp", "ah", "ipcomp", "default", "use", "require", "/", NULL -}; -enum token { - t_invalid = -1, t_discard, t_none, t_ipsec, t_entrust, t_bypass, - t_esp, t_ah, t_ipcomp, t_default, t_use, t_require, t_slash, t_omit, -}; -static int values[] = { - IPSEC_POLICY_DISCARD, IPSEC_POLICY_NONE, IPSEC_POLICY_IPSEC, - IPSEC_POLICY_ENTRUST, IPSEC_POLICY_BYPASS, - IPPROTO_ESP, IPPROTO_AH, IPPROTO_IPCOMP, - IPSEC_LEVEL_DEFAULT, IPSEC_LEVEL_USE, IPSEC_LEVEL_REQUIRE, 0, 0, -}; -struct pbuf { - char *buf; - int buflen; /* size of the buffer */ - int off; /* current offset */ -}; - -/* XXX duplicated def */ -static char *ipsp_strs[] = { - "discard", "none", "ipsec", "entrust", "bypass", -}; - -static enum token gettoken(char *p); -static char *skiptoken(char *p, enum token t); -static char *skipspaces(char *p); -static char *parse_request(struct pbuf *pbuf, char *p); -static char *parse_policy(struct pbuf *pbuf, char *p); -static char *get_sockaddr(char *host, struct sockaddr *addr); -static int parse_setreq(struct pbuf *pbuf, int proto, int level, - struct sockaddr *proxy); -static int parse_main(struct pbuf *pbuf, char *policy); - -static enum token gettoken(char *p) -{ - int i; - int l; - - assert(p); - for (i = 0; i < sizeof(tokens)/sizeof(tokens[0]); i++) { - if (tokens[i] == NULL) - continue; - l = strlen(tokens[i]); - if (strncmp(p, tokens[i], l) != 0) - continue; - /* slash alone is okay as token */ - if (i == t_slash) - return i; - /* other ones are words, so needs proper termination */ - if (isspace(p[l]) || p[l] == '/' || p[l] == '\0') - return i; - } - return t_invalid; -} - -static char *skiptoken(char *p, enum token t) -{ - assert(p); - assert(tokens[t] != NULL); - - if (gettoken(p) != t) - return NULL; - return p + strlen(tokens[t]); -} - -static char *skipspaces(char *p) -{ - assert(p); - while (p && isspace(*p)) - p++; - return p; -} - -static char *parse_request(struct pbuf *pbuf, char *p) -{ - enum token t; - int i; - enum token ts[3]; /* set of tokens */ - struct sockaddr_storage proxy; - int isproxy; - - assert(p); - assert(pbuf); - - i = 0; - - /* - * here, we accept sequence like: - * [token slash]* token - * and decode that into ts[]. - */ - for (i = 0; i < sizeof(ts)/sizeof(ts[0]); i++) - ts[i] = t_invalid; - i = 0; - while (i < sizeof(ts)/sizeof(ts[0])) { - /* get a token */ - p = skipspaces(p); - t = gettoken(p); - switch (t) { - case t_invalid: - /* - * this may be a proxy. - * this shouldn't be a termination. - */ - if (*p != '\0') - goto breakbreak; - goto parseerror; - case t_esp: - case t_ah: - case t_ipcomp: - case t_default: - case t_use: - case t_require: - /* - * protocol or level - just keep it into ts[], - * we'll care about protocol/level ordering afterwards - */ - ts[i++] = t; - p = skiptoken(p, t); - break; - case t_slash: - /* - * the user did not specify the token - don't advance - * the pointer. - */ - ts[i++] = t_omit; - break; - default: - /* bzz, you are wrong */ - goto parseerror; - } - - /* get a slash */ - p = skipspaces(p); - t = gettoken(p); - switch (t) { - case t_invalid: - /* this may be a termination. */ - if (*p == '\0') - goto breakbreak; - goto parseerror; - case t_esp: - case t_ah: - case t_ipcomp: - /* protocol - we've hit the next request */ - goto breakbreak; - case t_slash: - p = skiptoken(p, t); - break; - default: - /* bzz, you are wrong */ - return NULL; - } - } - -breakbreak: - - /* alright, we've got the tokens. */ - switch (i) { - case 0: - ipsec_errcode = EIPSEC_NO_PROTO; - return NULL; /* no token? naa, go away */ - case 1: - case 2: - if (!(ts[0] == t_esp || ts[0] == t_ah || ts[0] == t_ipcomp)) { - ipsec_errcode = EIPSEC_INVAL_PROTO; - return NULL; - } - if (i == 1) { - i++; - ts[1] = t_default; - } - if (ts[1] == t_omit) - ts[1] = t_default; - if (!(ts[1] == t_default || ts[1] == t_use - || ts[1] == t_require)) { - ipsec_errcode = EIPSEC_INVAL_LEVEL; - return NULL; - } - break; - default: - ipsec_errcode = EIPSEC_INVAL_LEVEL; /*XXX*/ - return NULL; - } - - /* here, we should be having 2 tokens */ - assert(i == 2); - - /* we may have a proxy here */ - isproxy = 0; - if (*p != '\0' && gettoken(p) == t_invalid) { - p = get_sockaddr(p, (struct sockaddr *)&proxy); - if (p == NULL) { - /* get_sockaddr updates ipsec_errcode */ - return NULL; - } - isproxy++; - p = skipspaces(p); - } - - if (parse_setreq(pbuf, values[ts[0]], values[ts[1]], - isproxy ? (struct sockaddr *)&proxy : NULL) < 0) { - /* parse_setreq updates ipsec_errcode */ - return NULL; - } - - return p; - -parseerror: - ipsec_errcode = EIPSEC_NO_ERROR; /*sentinel*/ - switch (i) { - case 0: - ipsec_errcode = EIPSEC_NO_PROTO; - break; - case 1: - case 2: - if (!(ts[0] == t_esp || ts[0] == t_ah || ts[0] == t_ipcomp)) - ipsec_errcode = EIPSEC_INVAL_PROTO; - if (i == 1) - break; - if (!(ts[1] == t_default || ts[1] == t_use - || ts[1] == t_require)) { - ipsec_errcode = EIPSEC_INVAL_LEVEL; - } - break; - } - if (ipsec_errcode == EIPSEC_NO_ERROR) - ipsec_errcode = EIPSEC_INVAL_LEVEL; /*XXX*/ - return NULL; -} - -static char *parse_policy(struct pbuf *pbuf, char *p) -{ - enum token t; - int len; - struct sadb_x_policy *policy; - - assert(p); - assert(pbuf); - ipsec_errcode = EIPSEC_NO_ERROR; - - /* get the token */ - p = skipspaces(p); - t = gettoken(p); - switch (t) { - case t_discard: - case t_none: - case t_ipsec: - case t_entrust: - case t_bypass: - p = skiptoken(p, t); - break; - default: - /* bzz, you're wrong */ - ipsec_errcode = EIPSEC_INVAL_POLICY; - return NULL; - } - - /* construct policy structure */ - len = PFKEY_ALIGN8(sizeof(*policy)); - policy = NULL; - if (pbuf->buf) { - if (pbuf->off + len > pbuf->buflen) { - /* buffer overflow */ - ipsec_errcode = EIPSEC_NO_BUFS; - return NULL; - } - - policy = (struct sadb_x_policy *)&pbuf->buf[pbuf->off]; - memset(policy, 0, sizeof(*policy)); - policy->sadb_x_policy_len = PFKEY_UNIT64(len); - /* update later */ - policy->sadb_x_policy_exttype = SADB_X_EXT_POLICY; - policy->sadb_x_policy_type = values[t]; - } - pbuf->off += len; - - /* alright, go to the next step */ - while (p && *p) - p = parse_request(pbuf, p); - - /* ipsec policy needs request */ - if (t == t_ipsec && pbuf->off == len) { - ipsec_errcode = EIPSEC_INVAL_POLICY; - return NULL; - } - - /* update length */ - if (policy) - policy->sadb_x_policy_len = PFKEY_UNIT64(pbuf->off); - - return p; -} - -static char *get_sockaddr(char *host, struct sockaddr *addr) -{ - struct sockaddr *saddr = NULL; - struct addrinfo hints, *res; - char *serv = NULL; - int error; - char *p, c; - - /* find the next delimiter */ - p = host; - while (p && *p && !isspace(*p) && *p != '/') - p++; - if (p == host) - return NULL; - c = *p; - *p = '\0'; - - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; - if ((error = getaddrinfo(host, serv, &hints, &res)) != 0) { - ipsec_set_strerror(gai_strerror(error)); - *p = c; - return NULL; - } - - if (res->ai_addr == NULL) { - ipsec_set_strerror(gai_strerror(error)); - *p = c; - return NULL; - } - -#if 0 - if (res->ai_next) { - printf("getaddrinfo(%s): " - "resolved to multiple address, taking the first one", - host); - } -#endif - - if ((saddr = malloc(res->ai_addr->sa_len)) == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; - freeaddrinfo(res); - *p = c; - return NULL; - } - memcpy(addr, res->ai_addr, res->ai_addr->sa_len); - - freeaddrinfo(res); - - ipsec_errcode = EIPSEC_NO_ERROR; - *p = c; - return p; -} - -static int parse_setreq(struct pbuf *pbuf, int proto, int level, - struct sockaddr *proxy) -{ - struct sadb_x_ipsecrequest *req; - int start; - int len; - - assert(pbuf); - - start = pbuf->off; - - len = PFKEY_ALIGN8(sizeof(*req)); - req = NULL; - if (pbuf->buf) { - if (pbuf->off + len > pbuf->buflen) { - /* buffer overflow */ - ipsec_errcode = EIPSEC_NO_BUFS; - return -1; - } - req = (struct sadb_x_ipsecrequest *)&pbuf->buf[pbuf->off]; - memset(req, 0, sizeof(*req)); - req->sadb_x_ipsecrequest_len = len; /* updated later */ - req->sadb_x_ipsecrequest_proto = proto; - req->sadb_x_ipsecrequest_mode = - (proxy == NULL ? IPSEC_MODE_TRANSPORT - : IPSEC_MODE_TUNNEL); - req->sadb_x_ipsecrequest_level = level; - - } - pbuf->off += len; - - if (proxy) { - len = PFKEY_ALIGN8(proxy->sa_len); - if (pbuf->buf) { - if (pbuf->off + len > pbuf->buflen) { - /* buffer overflow */ - ipsec_errcode = EIPSEC_NO_BUFS; - return -1; - } - memset(&pbuf->buf[pbuf->off], 0, len); - memcpy(&pbuf->buf[pbuf->off], proxy, proxy->sa_len); - } - if (req) - req->sadb_x_ipsecrequest_len += len; - pbuf->off += len; - } - - return 0; -} - -static int parse_main(struct pbuf *pbuf, char *policy) -{ - char *p; - - ipsec_errcode = EIPSEC_NO_ERROR; - - if (policy == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return -1; - } - - p = parse_policy(pbuf, policy); - if (!p) { - /* ipsec_errcode updated somewhere inside */ - return -1; - } - p = skipspaces(p); - if (*p != '\0') { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return -1; - } - - ipsec_errcode = EIPSEC_NO_ERROR; - return 0; -} - -/* %%% */ -int ipsec_get_policylen(char *policy) -{ - struct pbuf pbuf; - - memset(&pbuf, 0, sizeof(pbuf)); - if (parse_main(&pbuf, policy) < 0) - return -1; - - ipsec_errcode = EIPSEC_NO_ERROR; - return pbuf.off; -} - -int ipsec_set_policy(char *buf, int len, char *policy) -{ - struct pbuf pbuf; - - memset(&pbuf, 0, sizeof(pbuf)); - pbuf.buf = buf; - pbuf.buflen = len; - if (parse_main(&pbuf, policy) < 0) - return -1; - - ipsec_errcode = EIPSEC_NO_ERROR; - return pbuf.off; -} - -/* - * policy is sadb_x_policy buffer. - * Must call free() later. - * When delimiter == NULL, alternatively ' '(space) is applied. - */ -char *ipsec_dump_policy(char *policy, char *delimiter) -{ - struct sadb_x_policy *xpl = (struct sadb_x_policy *)policy; - struct sadb_x_ipsecrequest *xisr; - int xtlen, buflen; - char *buf; - - /* sanity check */ - if (policy == NULL) - return NULL; - if (xpl->sadb_x_policy_exttype != SADB_X_EXT_POLICY) { - ipsec_errcode = EIPSEC_INVAL_EXTTYPE; - return NULL; - } - - /* set delimiter */ - if (delimiter == NULL) - delimiter = " "; - - switch (xpl->sadb_x_policy_type) { - case IPSEC_POLICY_DISCARD: - case IPSEC_POLICY_NONE: - case IPSEC_POLICY_IPSEC: - case IPSEC_POLICY_BYPASS: - case IPSEC_POLICY_ENTRUST: - break; - default: - ipsec_errcode = EIPSEC_INVAL_POLICY; - return NULL; - } - - buflen = strlen(ipsp_strs[xpl->sadb_x_policy_type]) + 1; - - if ((buf = malloc(buflen)) == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; - return NULL; - } - strcpy(buf, ipsp_strs[xpl->sadb_x_policy_type]); - - if (xpl->sadb_x_policy_type != IPSEC_POLICY_IPSEC) { - ipsec_errcode = EIPSEC_NO_ERROR; - return buf; - } - - xtlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); - xisr = (struct sadb_x_ipsecrequest *)(policy + sizeof(*xpl)); - - /* count length of buffer for use */ - /* XXX non-seriously */ - while (xtlen > 0) { - buflen += 20; - if (xisr->sadb_x_ipsecrequest_mode ==IPSEC_MODE_TUNNEL) - buflen += 50; - xtlen -= xisr->sadb_x_ipsecrequest_len; - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr - + xisr->sadb_x_ipsecrequest_len); - } - - /* validity check */ - if (xtlen < 0) { - ipsec_errcode = EIPSEC_INVAL_SADBMSG; - free(buf); - return NULL; - } - - if ((buf = realloc(buf, buflen)) == NULL) { - ipsec_errcode = EIPSEC_NO_BUFS; - return NULL; - } - - xtlen = PFKEY_UNUNIT64(xpl->sadb_x_policy_len) - sizeof(*xpl); - xisr = (struct sadb_x_ipsecrequest *)(policy + sizeof(*xpl)); - - while (xtlen > 0) { - switch (xisr->sadb_x_ipsecrequest_proto) { - case IPPROTO_ESP: - strcat(buf, delimiter); - strcat(buf, "esp"); - break; - case IPPROTO_AH: - strcat(buf, delimiter); - strcat(buf, "ah"); - break; - case IPPROTO_IPCOMP: - strcat(buf, delimiter); - strcat(buf, "ipcomp"); - break; - default: - ipsec_errcode = EIPSEC_INVAL_PROTO; - free(buf); - return NULL; - } - - switch (xisr->sadb_x_ipsecrequest_level) { - case IPSEC_LEVEL_DEFAULT: - strcat(buf, "/default"); - break; - case IPSEC_LEVEL_USE: - strcat(buf, "/use"); - break; - case IPSEC_LEVEL_REQUIRE: - strcat(buf, "/require"); - break; - default: - ipsec_errcode = EIPSEC_INVAL_LEVEL; - free(buf); - return NULL; - } - - if (xisr->sadb_x_ipsecrequest_mode ==IPSEC_MODE_TUNNEL) { - char tmp[100]; /* XXX */ - struct sockaddr *saddr = - (struct sockaddr *)((caddr_t)xisr + sizeof(*xisr)); -#if 1 - inet_ntop(saddr->sa_family, _INADDRBYSA(saddr), - tmp, sizeof(tmp)); -#else - getnameinfo(saddr, saddr->sa_len, tmp, sizeof(tmp), - NULL, 0, NI_NUMERICHOST); -#endif - strcat(buf, "/"); - strcat(buf, tmp); - } - - xtlen -= xisr->sadb_x_ipsecrequest_len; - xisr = (struct sadb_x_ipsecrequest *)((caddr_t)xisr - + xisr->sadb_x_ipsecrequest_len); - } - - ipsec_errcode = EIPSEC_NO_ERROR; - return buf; -} diff --git a/lib/libipsec/ipsec_set_policy.3 b/lib/libipsec/ipsec_set_policy.3 index 8055215bd983..769803db59a6 100644 --- a/lib/libipsec/ipsec_set_policy.3 +++ b/lib/libipsec/ipsec_set_policy.3 @@ -25,8 +25,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $NetBSD: ipsec_set_policy.3,v 1.5 1999/12/21 14:17:18 itojun Exp $ -.\" KAME Id: ipsec_set_policy.3,v 1.1.2.6 1999/07/01 06:54:58 sakane Exp +.\" $NetBSD: ipsec_set_policy.3,v 1.6 2000/01/31 14:15:31 itojun Exp $ +.\" KAME Id: ipsec_set_policy.3,v 1.8 2000/01/27 17:59:12 itojun Exp .\" .Dd May 5, 1998 .Dt IPSEC_SET_POLICY 3 @@ -43,10 +43,10 @@ .\" .Sh SYNOPSIS .Fd #include +.Ft "char *" +.Fn ipsec_set_policy "char *policy" "int len" .Ft int -.Fn ipsec_set_policy "char *buf" "int len" "char *policy" -.Ft int -.Fn ipsec_get_policylen "char *policy" +.Fn ipsec_get_policylen "char *buf" .Ft "char *" .Fn ipsec_dump_policy "char *buf" "char *delim" .\" @@ -58,21 +58,18 @@ and/or .Li struct sadb_x_ipsecrequest from human-readable policy specification. policy specification must be given as C string -.Fa policy , -and the resulting structure will be generated at the buffer pointed to by -.Fa buf , -length -.Fa len . -.Pp -To obtain the required buffer size beforehand, use -.Fn ipsec_get_policylen -with the same .Fa policy -argument. +and length +.Fa len +of +.Fa policy . +.Fn ipsec_set_policy +will return the buffer of IPsec policy specification structure. +.Pp +You may want the length of the generated buffer such when calling +.Xr setsockopt 2 . .Fn ipsec_get_policylen -will return the required buffer size, -and you may want to allocate buffer dynamically for use with -.Fn ipsec_set_policy . +will return the length. .Pp .Fn ipsec_dump_policy converts IPsec policy structure into readable form. @@ -95,51 +92,99 @@ returns pointer to dynamically allocated string. It is caller's responsibility to reclaim the region, by using .Xr free 3 . .Pp +.\" .Fa policy is formatted as either of the following: .Bl -tag -width "discard" -.It Li discard -.Li discard -means the packet matching indexes will be discarded. -.It Li none -.Li none -means IPsec will not be performed on the matching packets +.It Ar direction Li entrust +.Ar direction +must be +.Li in +or +.Li out . +.Ar direction +specifies which direction the policy needs to be applied. +.Li entrust +means to consult to SPD defined by +.Xr setkey 8 . +.It Ar direction Li bypass +.Li bypass +means to be bypassed the IPsec processing. .Po packet will be transmitted in clear .Pc . -.It Xo Li ipsec -.Ar protocol -.Op Ar /level -.Op Ar /peer -.Op ... +This is for privileged socket. +.It Xo +.Ar direction +.Li ipsec +.Ar request ... .Xc .Li ipsec means that the matching packets are subject to IPsec processing. .Li ipsec -can be followed by multiple set of -.Do +can be followed by one or more +.Ar request +string, which is formatted as below: +.Bl -tag -width "discard" +.It Xo .Ar protocol +.Li / +.Ar mode +.Li / +.Ar src +.Li - +.Ar dst .Op Ar /level -.Op Ar /peer -.Dc -arguments. +.Xc .Ar protocol is either .Li ah , .Li esp or .Li ipcomp . +.Pp +.Ar mode +is either +.Li transport +or +.Li tunnel . +.Pp +.Ar src +and +.Ar dst +specifies IPsec endpoint. +.Ar src +always means +.Dq sending node +and +.Ar dst +always means +.Dq receiving node . +Therefore, when +.Ar direction +is +.Li in , +.Ar dst +is this node +and +.Ar src +is the other node +.Pq peer . +.Pp .Ar level must be set to one of the following: -.Li default , use +.Li default , use , require or -.Li require . +.Li unique . .Li default means that the kernel should consult the system default policy defined by .Xr sysctl 8 , such as .Li net.inet.ipsec.esp_trans_deflev . +See +.Xr ipsec 4 +regarding the system default. .Li use means that a relevant SA can be used when available, since the kernel may perform IPsec operation against packets when possible. @@ -150,14 +195,24 @@ or encrypted .Li require means that a relevant SA is required, since the kernel must perform IPsec operation against packets. -.Ar peer -is an IPv4 or IPv6 address string, and it will be used as -a hint when IPsec system configures IPsec tunnel mode SA by using -key management protocol. -.Pp -If the string is kept unambiguous, +.Li unique +is the same as +.Li require , +but adds the restriction that the SA for outbound traffic is used +only for this policy. +You may need the identifier in order to relate the policy and the SA +when you define the SA by manual keying. +You can put the decimal number as the identifier after +.Li unique +like +.Li unique : number . +.Li number +must be between 1 and 32767 . +If the +.Ar request +string is kept unambiguous, .Ar level -and slashes surrounding +and slash prior to .Ar level can be omitted. However, it is encouraged to specify them explicitly @@ -167,19 +222,31 @@ If is omitted, it will be interpreted as .Li default . .El +.El .Pp -Here are several examples: +Note that there is a bit difference of specification from +.Xr setkey 8 . +In specification by +.Xr setkey 8 , +both entrust and bypass are not used. Refer to +.Xr setkey 8 +for detail. +.Pp +Here are several examples +.Pq long lines are wrapped for readability : .Bd -literal -offset indent -discard -ipsec esp/require -ipsec ah/use/10.1.1.1 -ipsec esp/use ah/require -ipsec ipcomp/use esp/use ah/require +in discard +out ipsec esp/transport/10.1.1.1-10.1.1.2/require +in ipsec ah/transport/10.1.1.2-10.1.1.1/require +out ipsec esp/transport/10.1.1.2-10.1.1.1/use + ah/tunnel/10.1.1.2-10.1.1.1/unique:1000 +in ipsec ipcomp/transport/10.1.1.2-10.1.1.1/use + esp/transport/10.1.1.2-10.1.1.1/use .Ed .\" .Sh RETURN VALUES .Fn ipsec_set_policy -returns with 0 on success, negative value on errors. +returns a pointer to the allocated buffer of policy specification if successful; otherwise a NULL pointer is returned. .Fn ipsec_get_policylen returns with positive value .Pq meaning the buffer size @@ -192,6 +259,7 @@ on errors. .\" .Sh SEE ALSO .Xr ipsec_strerror 3 , +.Xr ispec 4 , .Xr setkey 8 .\" .Sh HISTORY diff --git a/lib/libipsec/ipsec_strerror.3 b/lib/libipsec/ipsec_strerror.3 index c34c62d58bef..c1292c9fbf04 100644 --- a/lib/libipsec/ipsec_strerror.3 +++ b/lib/libipsec/ipsec_strerror.3 @@ -25,8 +25,8 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $NetBSD: ipsec_strerror.3,v 1.5 1999/12/21 14:17:18 itojun Exp $ -.\" KAME Id: ipsec_strerror.3,v 1.1.2.1 1999/05/06 09:26:43 itojun Exp +.\" $NetBSD: ipsec_strerror.3,v 1.6 2000/01/31 14:15:31 itojun Exp $ +.\" KAME Id: ipsec_strerror.3,v 1.4 2000/01/27 17:59:13 itojun Exp .\" .Dd May 6, 1998 .Dt IPSEC_STRERROR 3 @@ -42,7 +42,7 @@ .Sh SYNOPSIS .Fd #include .Ft "char *" -.Fn ipsec_strerror "int code" +.Fn ipsec_strerror .\" .Sh DESCRIPTION .Pa netinet6/ipsec.h @@ -54,6 +54,19 @@ which is used to pass error code from IPsec policy manipulation library to user program. .Fn ipsec_strerror can be used to obtain error message string for the error code. +.Pp +The array pointed to is not to be modified by the program. +Since +.Fn ipsec_strerror +uses +.Xr strerror 3 +as underlying function, calling +.Xr strerror 3 +after +.Fn ipsec_strerror +would make the return value from +.Fn ipsec_strerror +invalid, or overwritten. .\" .Sh RETURN VALUES .Fn ipsec_strerror diff --git a/lib/libipsec/ipsec_strerror.c b/lib/libipsec/ipsec_strerror.c index 8bf0f117d815..33aad1712edc 100644 --- a/lib/libipsec/ipsec_strerror.c +++ b/lib/libipsec/ipsec_strerror.c @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_strerror.c,v 1.3 1999/07/04 01:36:13 itojun Exp $ */ +/* $NetBSD: ipsec_strerror.c,v 1.4 2000/01/31 14:15:31 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -46,7 +46,9 @@ static char *ipsec_errlist[] = { "Invalid sadb message", /*EIPSEC_INVAL_SADBMSG*/ "Invalid version", /*EIPSEC_INVAL_VERSION*/ "Invalid security policy", /*EIPSEC_INVAL_POLICY*/ +"Invalid address specification", /*EIPSEC_INVAL_ADDRESS*/ "Invalid ipsec protocol", /*EIPSEC_INVAL_PROTO*/ +"Invalid ipsec mode", /*EIPSEC_INVAL_MODE*/ "Invalid ipsec level", /*EIPSEC_INVAL_LEVEL*/ "Invalid SA type", /*EIPSEC_INVAL_SATYPE*/ "Invalid message type", /*EIPSEC_INVAL_MSGTYPE*/ @@ -55,6 +57,7 @@ static char *ipsec_errlist[] = { "Invalid key length", /*EIPSEC_INVAL_KEYLEN*/ "Invalid address family", /*EIPSEC_INVAL_FAMILY*/ "Invalid prefix length", /*EIPSEC_INVAL_PREFIXLEN*/ +"Invalid direciton", /*EIPSEC_INVAL_DIR*/ "SPI range violation", /*EIPSEC_INVAL_SPI*/ "No protocol specified", /*EIPSEC_NO_PROTO*/ "No algorithm specified", /*EIPSEC_NO_ALGS*/ @@ -62,6 +65,7 @@ static char *ipsec_errlist[] = { "Must get supported algorithms list first", /*EIPSEC_DO_GET_SUPP_LIST*/ "Protocol mismatch", /*EIPSEC_PROTO_MISMATCH*/ "Family mismatch", /*EIPSEC_FAMILY_MISMATCH*/ +"Too few arguments", /*EIPSEC_FEW_ARGUMENTS*/ NULL, /*EIPSEC_SYSTEM_ERROR*/ "Unknown error", /*EIPSEC_MAX*/ }; diff --git a/lib/libipsec/ipsec_strerror.h b/lib/libipsec/ipsec_strerror.h index 77b79686f3f6..2af442154de4 100644 --- a/lib/libipsec/ipsec_strerror.h +++ b/lib/libipsec/ipsec_strerror.h @@ -1,4 +1,4 @@ -/* $NetBSD: ipsec_strerror.h,v 1.3 1999/07/04 01:36:13 itojun Exp $ */ +/* $NetBSD: ipsec_strerror.h,v 1.4 2000/01/31 14:15:31 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -30,7 +30,7 @@ */ extern int ipsec_errcode; -extern void ipsec_set_strerror(char *str); +extern void ipsec_set_strerror __P((char *)); #define EIPSEC_NO_ERROR 0 /*success*/ #define EIPSEC_NOT_SUPPORTED 1 /*not supported*/ @@ -38,21 +38,25 @@ extern void ipsec_set_strerror(char *str); #define EIPSEC_INVAL_SADBMSG 3 /*invalid sadb message*/ #define EIPSEC_INVAL_VERSION 4 /*invalid version*/ #define EIPSEC_INVAL_POLICY 5 /*invalid security policy*/ -#define EIPSEC_INVAL_PROTO 6 /*invalid ipsec protocol*/ -#define EIPSEC_INVAL_LEVEL 7 /*invalid ipsec level*/ -#define EIPSEC_INVAL_SATYPE 8 /*invalid SA type*/ -#define EIPSEC_INVAL_MSGTYPE 9 /*invalid message type*/ -#define EIPSEC_INVAL_EXTTYPE 10 /*invalid extension type*/ -#define EIPSEC_INVAL_ALGS 11 /*Invalid algorithm type*/ -#define EIPSEC_INVAL_KEYLEN 12 /*invalid key length*/ -#define EIPSEC_INVAL_FAMILY 13 /*invalid address family*/ -#define EIPSEC_INVAL_PREFIXLEN 14 /*SPI range violation*/ -#define EIPSEC_INVAL_SPI 15 /*invalid prefixlen*/ -#define EIPSEC_NO_PROTO 16 /*no protocol specified*/ -#define EIPSEC_NO_ALGS 17 /*No algorithm specified*/ -#define EIPSEC_NO_BUFS 18 /*no buffers available*/ -#define EIPSEC_DO_GET_SUPP_LIST 19 /*must get supported algorithm first*/ -#define EIPSEC_PROTO_MISMATCH 20 /*protocol mismatch*/ -#define EIPSEC_FAMILY_MISMATCH 21 /*family mismatch*/ -#define EIPSEC_SYSTEM_ERROR 22 /*system error*/ -#define EIPSEC_MAX 23 /*unknown error*/ +#define EIPSEC_INVAL_ADDRESS 6 /*invalid address specification*/ +#define EIPSEC_INVAL_PROTO 7 /*invalid ipsec protocol*/ +#define EIPSEC_INVAL_MODE 8 /*Invalid ipsec mode*/ +#define EIPSEC_INVAL_LEVEL 9 /*invalid ipsec level*/ +#define EIPSEC_INVAL_SATYPE 10 /*invalid SA type*/ +#define EIPSEC_INVAL_MSGTYPE 11 /*invalid message type*/ +#define EIPSEC_INVAL_EXTTYPE 12 /*invalid extension type*/ +#define EIPSEC_INVAL_ALGS 13 /*Invalid algorithm type*/ +#define EIPSEC_INVAL_KEYLEN 14 /*invalid key length*/ +#define EIPSEC_INVAL_FAMILY 15 /*invalid address family*/ +#define EIPSEC_INVAL_PREFIXLEN 16 /*SPI range violation*/ +#define EIPSEC_INVAL_DIR 17 /*Invalid direciton*/ +#define EIPSEC_INVAL_SPI 18 /*invalid prefixlen*/ +#define EIPSEC_NO_PROTO 19 /*no protocol specified*/ +#define EIPSEC_NO_ALGS 20 /*No algorithm specified*/ +#define EIPSEC_NO_BUFS 21 /*no buffers available*/ +#define EIPSEC_DO_GET_SUPP_LIST 22 /*must get supported algorithm first*/ +#define EIPSEC_PROTO_MISMATCH 23 /*protocol mismatch*/ +#define EIPSEC_FAMILY_MISMATCH 24 /*family mismatch*/ +#define EIPSEC_FEW_ARGUMENTS 25 /*Too few arguments*/ +#define EIPSEC_SYSTEM_ERROR 26 /*system error*/ +#define EIPSEC_MAX 27 /*unknown error*/ diff --git a/lib/libipsec/pfkey.c b/lib/libipsec/pfkey.c index 6f32dceab88d..be60978802b0 100644 --- a/lib/libipsec/pfkey.c +++ b/lib/libipsec/pfkey.c @@ -1,4 +1,4 @@ -/* $NetBSD: pfkey.c,v 1.5 1999/09/16 04:20:03 itojun Exp $ */ +/* $NetBSD: pfkey.c,v 1.6 2000/01/31 14:15:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -29,15 +29,6 @@ * SUCH DAMAGE. */ -#if 0 -static char *rcsid = "@(#) pfkey.c KAME Revision: 1.1.4.11"; -#else -#include -#ifndef lint -__RCSID("$NetBSD: pfkey.c,v 1.5 1999/09/16 04:20:03 itojun Exp $"); -#endif -#endif - #include #include #include @@ -45,6 +36,7 @@ __RCSID("$NetBSD: pfkey.c,v 1.5 1999/09/16 04:20:03 itojun Exp $"); #include #include #include +#include #include #include @@ -55,32 +47,29 @@ __RCSID("$NetBSD: pfkey.c,v 1.5 1999/09/16 04:20:03 itojun Exp $"); #define CALLOC(size, cast) (cast)calloc(1, (size)) -static int pfkey_send_x1( int so, u_int type, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - struct sockaddr *proxy, - u_int32_t spi, caddr_t keymat, +static int pfkey_send_x1 __P((int so, u_int type, u_int satype, u_int mode, + struct sockaddr *src, struct sockaddr *dst, u_int32_t spi, + u_int32_t reqid, u_int wsize, + caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type, u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq); -static int pfkey_send_x2( int so, u_int type, u_int satype, - struct sockaddr *src, u_int prefs, - struct sockaddr *dst, u_int prefd, u_int proto, - u_int32_t spi); + u_int32_t l_addtime, u_int32_t l_usetime, u_int32_t seq)); +static int pfkey_send_x2 __P((int so, u_int type, u_int satype, u_int mode, + struct sockaddr *src, struct sockaddr *dst, u_int32_t spi)); +static int pfkey_send_x3 __P((int so, u_int type, u_int satype)); -static int pfkey_send_x3(int so, u_int type, u_int satype); - -static caddr_t pfkey_setsadbaddr(caddr_t buf, u_int type, - u_int family, caddr_t addr, - u_int pref, u_int proto, u_int port); +static caddr_t pfkey_setsadbmsg __P((caddr_t buf, u_int type, u_int tlen, + u_int satype, u_int mode, u_int32_t reqid, u_int32_t seq, pid_t pid)); +static caddr_t pfkey_setsadbsa __P((caddr_t buf, u_int32_t spi, u_int wsize, + u_int auth, u_int enc, u_int32_t flags)); +static caddr_t pfkey_setsadbaddr __P((caddr_t buf, u_int exttype, + struct sockaddr *saddr, u_int prefixlen, u_int ul_proto)); static caddr_t pfkey_setsadbkey(caddr_t buf, u_int type, - caddr_t key, u_int keylen); -static caddr_t pfkey_setsadbsa(caddr_t buf, caddr_t spi, - u_int a_type, u_int e_type, u_int flags); + caddr_t key, u_int keylen); static caddr_t pfkey_setsadblifetime(caddr_t buf, u_int type, - u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime); + u_int32_t l_alloc, u_int32_t l_bytes, + u_int32_t l_addtime, u_int32_t l_usetime); /* * check key length against algorithm specified. @@ -91,9 +80,13 @@ static caddr_t pfkey_setsadblifetime(caddr_t buf, u_int type, * -1: invalid. * 0: valid. */ -static struct sadb_msg *ipsec_supported = NULL; +struct sadb_msg *ipsec_supported = NULL; -int ipsec_check_keylen(u_int supported, u_int alg_id, u_int keylen) +int +ipsec_check_keylen(supported, alg_id, keylen) + u_int supported; + u_int alg_id; + u_int keylen; { u_int tlen; caddr_t p; @@ -157,19 +150,938 @@ int ipsec_check_keylen(u_int supported, u_int alg_id, u_int keylen) } /* - * check basic usage for sadb_msg, - * and set the pointer to each header in this message buffer. - * NOTE: This routine is derived from netkey/key.c in KAME. + * set the rate for SOFT lifetime against HARD one. + * If rate is more than 100 or equal to zero, then set to 100. + */ +static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; +static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; + +u_int +pfkey_set_softrate(type, rate) + u_int type, rate; +{ + ipsec_errcode = EIPSEC_NO_ERROR; + + if (rate > 100 || rate == 0) + rate = 100; + + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + soft_lifetime_allocations_rate = rate; + return 0; + case SADB_X_LIFETIME_BYTES: + soft_lifetime_bytes_rate = rate; + return 0; + case SADB_X_LIFETIME_ADDTIME: + soft_lifetime_addtime_rate = rate; + return 0; + case SADB_X_LIFETIME_USETIME: + soft_lifetime_usetime_rate = rate; + return 0; + } + + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return 1; +} + +/* + * get current rate for SOFT lifetime against HARD one. + * ATTENTION: ~0 is returned if invalid type was passed. + */ +u_int +pfkey_get_softrate(type) + u_int type; +{ + switch (type) { + case SADB_X_LIFETIME_ALLOCATIONS: + return soft_lifetime_allocations_rate; + case SADB_X_LIFETIME_BYTES: + return soft_lifetime_bytes_rate; + case SADB_X_LIFETIME_ADDTIME: + return soft_lifetime_addtime_rate; + case SADB_X_LIFETIME_USETIME: + return soft_lifetime_usetime_rate; + } + + return ~0; +} + +/* + * sending SADB_GETSPI message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_getspi(so, satype, mode, src, dst, min, max, reqid, seq) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t min, max, reqid, seq; +{ + struct sadb_msg *newmsg; + int len; + int need_spirange = 0; + caddr_t p; + + /* validity check */ + if (src == NULL || dst == NULL) { + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (min > max || (min > 0 && min <= 255)) { + ipsec_errcode = EIPSEC_INVAL_SPI; + return -1; + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if (min > 255 && max < ~0) { + need_spirange++; + len += sizeof(struct sadb_spirange); + } + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_GETSPI, + len, satype, mode, reqid, seq, getpid()); + + /* set sadb_address for source */ + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + src, + _INALENBYAF(src->sa_family) << 3, + IPSEC_ULPROTO_ANY); + + /* set sadb_address for destination */ + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + dst, + _INALENBYAF(dst->sa_family) << 3, + IPSEC_ULPROTO_ANY); + + /* proccessing spi range */ + if (need_spirange) { + int _len = sizeof(struct sadb_spirange); + +#define _SADB_SPIRANGE(p) ((struct sadb_spirange *)(p)) + _SADB_SPIRANGE(p)->sadb_spirange_len = PFKEY_UNIT64(_len); + _SADB_SPIRANGE(p)->sadb_spirange_exttype = SADB_EXT_SPIRANGE; + _SADB_SPIRANGE(p)->sadb_spirange_min = min; + _SADB_SPIRANGE(p)->sadb_spirange_max = max; +#undef _SADB_SPIRANGE(p) + p += _len; + } + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_UPDATE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_update(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_UPDATE, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_ADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_add(so, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int satype, mode, wsize; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc; + u_int64_t l_bytes, l_addtime, l_usetime; + u_int32_t seq; +{ + int len; + if ((len = pfkey_send_x1(so, SADB_ADD, satype, mode, src, dst, spi, + reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DELETE message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_delete(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_GET message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_get(so, satype, mode, src, dst, spi) + int so; + u_int satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + int len; + if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_REGISTER message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_register(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) + return -1; + + return len; +} + +/* + * receiving SADB_REGISTER message from the kernel, and copy buffer for + * sadb_supported returned into ipsec_supported. + * OUT: + * 0: success and return length sent. + * -1: error occured, and set errno. + */ +int +pfkey_recv_register(so) + int so; +{ + pid_t pid = getpid(); + struct sadb_msg *newmsg; + struct sadb_supported *sup; + caddr_t p; + int tlen; + + /* receive message */ + do { + if ((newmsg = pfkey_recv(so)) == NULL) + return -1; + + } while (newmsg->sadb_msg_type != SADB_REGISTER + || newmsg->sadb_msg_pid != pid); + + /* check and fix */ + newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); + + tlen = newmsg->sadb_msg_len - sizeof(struct sadb_msg); + p = (caddr_t)newmsg + sizeof(struct sadb_msg); + while (tlen > 0) { + sup = (struct sadb_supported *)p; + switch (sup->sadb_supported_exttype) { + case SADB_EXT_SUPPORTED_AUTH: + case SADB_EXT_SUPPORTED_ENCRYPT: + sup->sadb_supported_len = PFKEY_EXTLEN(sup); + break; + default: + ipsec_errcode = EIPSEC_INVAL_SATYPE; + free(newmsg); + return -1; + } + + tlen -= sup->sadb_supported_len; + p += sup->sadb_supported_len; + } + + if (tlen < 0) { + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + if (ipsec_supported != NULL) + free(ipsec_supported); + + ipsec_supported = newmsg; + + ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * sending SADB_FLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_flush(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_DUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_dump(so, satype) + int so; + u_int satype; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_PROMISC message to the kernel. + * NOTE that this function handles promisc mode toggle only. + * IN: + * flag: set promisc off if zero, set promisc on if non-zero. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + * 0 : error occured, and set errno. + * others: a pointer to new allocated buffer in which supported + * algorithms is. + */ +int +pfkey_send_promisc_toggle(so, flag) + int so; + int flag; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) + return -1; + + return len; +} + +/* + * sending SADB_X_SPDADD message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdadd(so, src, prefs, dst, prefd, proto, policy, policylen, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + char *policy; + int policylen; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + + /* validity check */ + if (src == NULL || dst == NULL) { + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (prefs > (_INALENBYAF(src->sa_family) << 3) + || prefd > (_INALENBYAF(dst->sa_family) << 3)) { + ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) + + policylen; + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_X_SPDADD, len, + SADB_SATYPE_UNSPEC, IPSEC_MODE_ANY, 0, + seq, getpid()); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + src, + prefs, + proto); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + dst, + prefd, + proto); + memcpy(p, policy, policylen); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_X_SPDDELETE message to the kernel. + * The length of key material is a_keylen + e_keylen. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddelete(so, src, prefs, dst, prefd, proto, seq) + int so; + struct sockaddr *src, *dst; + u_int prefs, prefd, proto; + u_int32_t seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + + /* validity check */ + if (src == NULL || dst == NULL) { + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + if (prefs > (_INALENBYAF(src->sa_family) << 3) + || prefd > (_INALENBYAF(dst->sa_family) << 3)) { + ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, SADB_X_SPDDELETE, len, + SADB_SATYPE_UNSPEC, IPSEC_MODE_ANY, 0, + seq, getpid()); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + src, + prefs, + proto); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + dst, + prefd, + proto); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_SPDFLUSH message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spdflush(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* + * sending SADB_SPDDUMP message to the kernel. + * OUT: + * positive: success and return length sent. + * -1 : error occured, and set errno. + */ +int +pfkey_send_spddump(so) + int so; +{ + int len; + + if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0) + return -1; + + return len; +} + +/* sending SADB_ADD or SADB_UPDATE message to the kernel */ +static int +pfkey_send_x1(so, type, satype, mode, src, dst, spi, reqid, wsize, + keymat, e_type, e_keylen, a_type, a_keylen, flags, + l_alloc, l_bytes, l_addtime, l_usetime, seq) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi, reqid; + u_int wsize; + caddr_t keymat; + u_int e_type, e_keylen, a_type, a_keylen, flags; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime, seq; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + + /* validity check */ + if (src == NULL || dst == NULL) { + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + switch (satype) { + case SADB_SATYPE_ESP: + if (e_type == SADB_EALG_NONE) { + ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_SATYPE_AH: + if (e_type != SADB_EALG_NONE) { + ipsec_errcode = EIPSEC_INVAL_ALGS; + return -1; + } + if (a_type == SADB_AALG_NONE) { + ipsec_errcode = EIPSEC_NO_ALGS; + return -1; + } + break; + case SADB_X_SATYPE_IPCOMP: + break; + default: + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len) + + sizeof(struct sadb_lifetime) + + sizeof(struct sadb_lifetime); + + if (e_type != SADB_EALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); + if (a_type != SADB_AALG_NONE) + len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, + satype, mode, reqid, seq, getpid()); + p = pfkey_setsadbsa(p, spi, wsize, a_type, e_type, flags); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + src, + _INALENBYAF(src->sa_family) << 3, + IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + dst, + _INALENBYAF(dst->sa_family) << 3, + IPSEC_ULPROTO_ANY); + + if (e_type != SADB_EALG_NONE) + p = pfkey_setsadbkey(p, SADB_EXT_KEY_ENCRYPT, + keymat, e_keylen); + if (a_type != SADB_AALG_NONE) + p = pfkey_setsadbkey(p, SADB_EXT_KEY_AUTH, + keymat + e_keylen, a_keylen); + + /* set sadb_lifetime for destination */ + p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_HARD, + l_alloc, l_bytes, l_addtime, l_usetime); + p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_SOFT, + l_alloc, l_bytes, l_addtime, l_usetime); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* sending SADB_DELETE or SADB_GET message to the kernel */ +static int +pfkey_send_x2(so, type, satype, mode, src, dst, spi) + int so; + u_int type, satype, mode; + struct sockaddr *src, *dst; + u_int32_t spi; +{ + struct sadb_msg *newmsg; + int len; + caddr_t p; + + /* validity check */ + if (src == NULL || dst == NULL) { + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + if (src->sa_family != dst->sa_family) { + ipsec_errcode = EIPSEC_FAMILY_MISMATCH; + return -1; + } + + /* create new sadb_msg to reply. */ + len = sizeof(struct sadb_msg) + + sizeof(struct sadb_sa) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(src->sa_len) + + sizeof(struct sadb_address) + + PFKEY_ALIGN8(dst->sa_len); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + p = pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, mode, 0, 0, getpid()); + p = pfkey_setsadbsa(p, spi, 0, 0, 0, 0); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_SRC, + src, + _INALENBYAF(src->sa_family) << 3, + IPSEC_ULPROTO_ANY); + p = pfkey_setsadbaddr(p, + SADB_EXT_ADDRESS_DST, + dst, + _INALENBYAF(dst->sa_family) << 3, + IPSEC_ULPROTO_ANY); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message + * to the kernel + */ +static int +pfkey_send_x3(so, type, satype) + int so; + u_int type, satype; +{ + struct sadb_msg *newmsg; + int len; + + /* validity check */ + switch (type) { + case SADB_X_PROMISC: + if (satype != 0 && satype != 1) { + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + default: + switch (satype) { + case SADB_SATYPE_UNSPEC: + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + break; + default: + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + } + + /* create new sadb_msg to send. */ + len = sizeof(struct sadb_msg); + + if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + (void)pfkey_setsadbmsg((caddr_t)newmsg, type, len, satype, 0, 0, 0, getpid()); + + /* send message */ + len = pfkey_send(so, newmsg, len); + free(newmsg); + + if (len < 0) + return -1; + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * open a socket. + * OUT: + * -1: fail. + * others : success and return value of socket. + */ +int +pfkey_open() +{ + int so; + const int bufsiz = 128 * 1024; /*is 128K enough?*/ + + if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + /* + * This is a temporary workaround for KAME PR 154. + * Don't really care even if it fails. + */ + (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); + (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); + + ipsec_errcode = EIPSEC_NO_ERROR; + return so; +} + +/* + * close a socket. + * OUT: + * 0: success. + * -1: fail. + */ +void +pfkey_close(so) + int so; +{ + (void)close(so); + + ipsec_errcode = EIPSEC_NO_ERROR; + return; +} + +/* + * receive sadb_msg data, and return pointer to new buffer allocated. + * Must free this buffer later. + * OUT: + * NULL : error occured. + * others : a pointer to sadb_msg structure. + */ +struct sadb_msg * +pfkey_recv(so) + int so; +{ + struct sadb_msg buf, *newmsg; + int len, reallen; + + while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { + if (errno == EINTR) continue; + ipsec_set_strerror(strerror(errno)); + return NULL; + } + + if (len < sizeof(buf)) { + recv(so, (caddr_t)&buf, sizeof(buf), 0); + ipsec_errcode = EIPSEC_MAX; + return NULL; + } + + /* read real message */ + reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); + if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { + ipsec_set_strerror(strerror(errno)); + return NULL; + } + + while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { + if (errno == EINTR) continue; + ipsec_set_strerror(strerror(errno)); + free(newmsg); + return NULL; + } + + if (len != reallen) { + ipsec_errcode = EIPSEC_SYSTEM_ERROR; + free(newmsg); + return NULL; + } + + ipsec_errcode = EIPSEC_NO_ERROR; + return newmsg; +} + +/* + * send message to a socket. + * OUT: + * others: success and return length sent. + * -1 : fail. + */ +int +pfkey_send(so, msg, len) + int so; + struct sadb_msg *msg; + int len; +{ + if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { + ipsec_set_strerror(strerror(errno)); + return -1; + } + + ipsec_errcode = EIPSEC_NO_ERROR; + return len; +} + +/* + * %%% Utilities + * NOTE: These functions are derived from netkey/key.c in KAME. + */ +/* + * set the pointer to each header in this message buffer. * IN: msg: pointer to message buffer. * mhp: pointer to the buffer initialized like below: - * * caddr_t mhp[SADB_EXT_MAX + 1]; - * * OUT: -1: invalid. * 0: valid. */ -int pfkey_check(struct sadb_msg *msg, caddr_t *mhp) +int +pfkey_align(msg, mhp) + struct sadb_msg *msg; + caddr_t *mhp; { + struct sadb_ext *ext; + int tlen, extlen; + int i; + /* validity check */ if (msg == NULL || mhp == NULL) { ipsec_errcode = EIPSEC_INVAL_ARGUMENT; @@ -177,65 +1089,11 @@ int pfkey_check(struct sadb_msg *msg, caddr_t *mhp) } /* initialize */ - { - int i; for (i = 0; i < SADB_EXT_MAX + 1; i++) mhp[i] = NULL; - } - - /* check version */ - if (msg->sadb_msg_version != PF_KEY_V2) { - ipsec_errcode = EIPSEC_INVAL_VERSION; - return -1; - } - - /* check type */ - if (msg->sadb_msg_type > SADB_MAX) { - ipsec_errcode = EIPSEC_INVAL_MSGTYPE; - return -1; - } - - /* check SA type */ - switch (msg->sadb_msg_satype) { - case SADB_SATYPE_UNSPEC: - if (msg->sadb_msg_type != SADB_REGISTER - && msg->sadb_msg_type != SADB_FLUSH - && msg->sadb_msg_type != SADB_DUMP - && msg->sadb_msg_type != SADB_X_PROMISC - && msg->sadb_msg_type != SADB_X_SPDADD - && msg->sadb_msg_type != SADB_X_SPDDELETE - && msg->sadb_msg_type != SADB_X_SPDDUMP - && msg->sadb_msg_type != SADB_X_SPDFLUSH) { - ipsec_errcode = EIPSEC_INVAL_SATYPE; - return -1; - } - - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_IPCOMP: - break; - case SADB_SATYPE_RSVP: - case SADB_SATYPE_OSPFV2: - case SADB_SATYPE_RIPV2: - case SADB_SATYPE_MIP: - ipsec_errcode = EIPSEC_NOT_SUPPORTED; - return -1; - - case 1: - if (msg->sadb_msg_type == SADB_X_PROMISC) - break; - /* FALLTHROUGH */ - default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; - return -1; - } mhp[0] = (caddr_t)msg; - { - struct sadb_ext *ext; - int tlen, extlen; - tlen = PFKEY_UNUNIT64(msg->sadb_msg_len) - sizeof(struct sadb_msg); ext = (struct sadb_ext *)((caddr_t)msg + sizeof(struct sadb_msg)); @@ -275,35 +1133,119 @@ int pfkey_check(struct sadb_msg *msg, caddr_t *mhp) return -1; } - extlen = PFKEY_UNUNIT64(ext->sadb_ext_len); + extlen = PFKEY_EXTLEN(ext); tlen -= extlen; ext = (struct sadb_ext *)((caddr_t)ext + extlen); } - } + + ipsec_errcode = EIPSEC_NO_ERROR; + return 0; +} + +/* + * check basic usage for sadb_msg, + * NOTE: This routine is derived from netkey/key.c in KAME. + * IN: msg: pointer to message buffer. + * mhp: pointer to the buffer initialized like below: + * + * caddr_t mhp[SADB_EXT_MAX + 1]; + * + * OUT: -1: invalid. + * 0: valid. + */ +int +pfkey_check(mhp) + caddr_t *mhp; +{ + struct sadb_msg *msg; + + /* validity check */ + if (mhp == NULL || mhp[0] == NULL) { + ipsec_errcode = EIPSEC_INVAL_ARGUMENT; + return -1; + } + + msg = (struct sadb_msg *)mhp[0]; + + /* check version */ + if (msg->sadb_msg_version != PF_KEY_V2) { + ipsec_errcode = EIPSEC_INVAL_VERSION; + return -1; + } + + /* check type */ + if (msg->sadb_msg_type > SADB_MAX) { + ipsec_errcode = EIPSEC_INVAL_MSGTYPE; + return -1; + } + + /* check SA type */ + switch (msg->sadb_msg_satype) { + case SADB_SATYPE_UNSPEC: + switch (msg->sadb_msg_type) { + case SADB_GETSPI: + case SADB_UPDATE: + case SADB_ADD: + case SADB_DELETE: + case SADB_GET: + case SADB_ACQUIRE: + case SADB_EXPIRE: + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_ESP: + case SADB_SATYPE_AH: + case SADB_X_SATYPE_IPCOMP: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDDUMP: + case SADB_X_SPDFLUSH: + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + ipsec_errcode = EIPSEC_NOT_SUPPORTED; + return -1; + case 1: /* XXX: What does it do ? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + ipsec_errcode = EIPSEC_INVAL_SATYPE; + return -1; + } /* check field of upper layer protocol and address family */ if (mhp[SADB_EXT_ADDRESS_SRC] != NULL && mhp[SADB_EXT_ADDRESS_DST] != NULL) { struct sadb_address *src0, *dst0; - struct sockaddr *src, *dst; src0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_SRC]); dst0 = (struct sadb_address *)(mhp[SADB_EXT_ADDRESS_DST]); - src = (struct sockaddr *)((caddr_t)src0 + sizeof(*src0)); - dst = (struct sockaddr *)((caddr_t)dst0 + sizeof(*dst0)); if (src0->sadb_address_proto != dst0->sadb_address_proto) { ipsec_errcode = EIPSEC_PROTO_MISMATCH; return -1; } - if (src->sa_family != dst->sa_family) { + if (PFKEY_ADDR_SADDR(src0)->sa_family + != PFKEY_ADDR_SADDR(dst0)->sa_family) { ipsec_errcode = EIPSEC_FAMILY_MISMATCH; return -1; } - if (src->sa_family != AF_INET - && src->sa_family != AF_INET6) { + switch (PFKEY_ADDR_SADDR(src0)->sa_family) { + case AF_INET: + case AF_INET6: + break; + default: ipsec_errcode = EIPSEC_INVAL_FAMILY; return -1; } @@ -319,915 +1261,121 @@ int pfkey_check(struct sadb_msg *msg, caddr_t *mhp) } /* - * set the rate for SOFT lifetime against HARD one. - * If rate is more than 100 or equal to zero, then set to 100. + * set data into sadb_msg. + * `buf' must has been allocated sufficiently. */ -static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE; -static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE; -static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE; -static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE; - -u_int pfkey_set_softrate(u_int type, u_int rate) +static caddr_t +pfkey_setsadbmsg(buf, type, tlen, satype, mode, reqid, seq, pid) + caddr_t buf; + u_int type, satype, mode; + u_int tlen; + u_int32_t reqid, seq; + pid_t pid; { - ipsec_errcode = EIPSEC_NO_ERROR; + struct sadb_msg *p; + u_int len; - if (rate > 100 || rate == 0) - rate = 100; - - switch (type) { - case SADB_X_LIFETIME_ALLOCATIONS: - soft_lifetime_allocations_rate = rate; - return 0; - case SADB_X_LIFETIME_BYTES: - soft_lifetime_bytes_rate = rate; - return 0; - case SADB_X_LIFETIME_ADDTIME: - soft_lifetime_addtime_rate = rate; - return 0; - case SADB_X_LIFETIME_USETIME: - soft_lifetime_usetime_rate = rate; - return 0; - } - - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return 1; -} - -/* - * get current rate for SOFT lifetime against HARD one. - * ATTENTION: ~0 is returned if invalid type was passed. - */ -u_int pfkey_get_softrate(u_int type) -{ - switch (type) { - case SADB_X_LIFETIME_ALLOCATIONS: - return soft_lifetime_allocations_rate; - case SADB_X_LIFETIME_BYTES: - return soft_lifetime_bytes_rate; - case SADB_X_LIFETIME_ADDTIME: - return soft_lifetime_addtime_rate; - case SADB_X_LIFETIME_USETIME: - return soft_lifetime_usetime_rate; - } - - return ~0; -} - -/* - * sending SADB_GETSPI message to the kernel. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_getspi( - int so, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, - u_int32_t min, - u_int32_t max, - u_int32_t seq) -{ - struct sadb_msg *newmsg; - int len; - int need_spirange = 0; - caddr_t p; - - /* validity check */ - if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return -1; - } - if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; - return -1; - } - if (prefs > _INALENBYAF(src->sa_family) * 8 - || prefd > _INALENBYAF(dst->sa_family) * 8) { - ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; - return -1; - } - if (min > max || (min > 0 && min <= 255)) { - ipsec_errcode = EIPSEC_INVAL_SPI; - return -1; - } - - /* create new sadb_msg to send. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)); - - if (min > 255 && max < ~0) { - need_spirange++; - len += sizeof(struct sadb_spirange); - } - - if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); - return -1; - } - - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = SADB_GETSPI; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = satype; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_seq = seq; - newmsg->sadb_msg_pid = getpid(); - p = (caddr_t)newmsg + sizeof(*newmsg); - - /* set sadb_address for source */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, - src->sa_family, - _INADDRBYSA(src), - prefs, - proto, - _INPORTBYSA(src)); - - /* set sadb_address for destination */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, - dst->sa_family, - _INADDRBYSA(dst), - prefd, - proto, - _INPORTBYSA(dst)); - - /* proccessing spi range */ - if (need_spirange) { - int _len = sizeof(struct sadb_spirange); - -#define _SADB_SPIRANGE(p) ((struct sadb_spirange *)(p)) - _SADB_SPIRANGE(p)->sadb_spirange_len = PFKEY_UNIT64(_len); - _SADB_SPIRANGE(p)->sadb_spirange_exttype = SADB_EXT_SPIRANGE; - _SADB_SPIRANGE(p)->sadb_spirange_min = min; - _SADB_SPIRANGE(p)->sadb_spirange_max = max; -#undef _SADB_SPIRANGE(p) - p += _len; - } - - /* send message */ - len = pfkey_send(so, newmsg, len); - free(newmsg); - - if (len < 0) - return -1; - - ipsec_errcode = EIPSEC_NO_ERROR; - return len; -} - -/* - * sending SADB_UPDATE message to the kernel. - * The length of key material is a_keylen + e_keylen. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_update( - int so, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, - struct sockaddr *proxy, - u_int32_t spi, - caddr_t keymat, - u_int e_type, - u_int e_keylen, - u_int a_type, - u_int a_keylen, - u_int flags, - u_int32_t l_alloc, - u_int32_t l_bytes, - u_int32_t l_addtime, - u_int32_t l_usetime, - u_int32_t seq) -{ - int len; - if ((len = pfkey_send_x1(so, SADB_UPDATE, - satype, src, prefs, dst, prefd, proto, proxy, spi, - keymat, e_type, e_keylen, a_type, a_keylen, flags, - l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) - return -1; - - return len; -} - -/* - * sending SADB_ADD message to the kernel. - * The length of key material is a_keylen + e_keylen. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_add( - int so, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, - struct sockaddr *proxy, - u_int32_t spi, - caddr_t keymat, - u_int e_type, - u_int e_keylen, - u_int a_type, - u_int a_keylen, - u_int flags, - u_int32_t l_alloc, - u_int32_t l_bytes, - u_int32_t l_addtime, - u_int32_t l_usetime, - u_int32_t seq) -{ - int len; - if ((len = pfkey_send_x1(so, SADB_ADD, - satype, src, prefs, dst, prefd, proto, proxy, spi, - keymat, e_type, e_keylen, a_type, a_keylen, flags, - l_alloc, l_bytes, l_addtime, l_usetime, seq)) < 0) - return -1; - - return len; -} - -/* - * sending SADB_DELETE message to the kernel. - * The length of key material is a_keylen + e_keylen. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_delete( - int so, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, - u_int32_t spi) -{ - int len; - if ((len = pfkey_send_x2(so, SADB_DELETE, - satype, src, prefs, dst, prefd, proto, spi)) < 0) - return -1; - - return len; -} - -/* - * sending SADB_GET message to the kernel. - * The length of key material is a_keylen + e_keylen. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_get( - int so, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, - u_int32_t spi) -{ - int len; - if ((len = pfkey_send_x2(so, SADB_GET, - satype, src, prefs, dst, prefd, proto, spi)) < 0) - return -1; - - return len; -} - -/* - * sending SADB_REGISTER message to the kernel. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_register(int so, u_int satype) -{ - int len; - - if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0) - return -1; - - return len; -} - -/* - * receiving SADB_REGISTER message from the kernel, and copy buffer for - * sadb_supported returned into ipsec_supported. - * OUT: - * 0: success and return length sent. - * -1: error occured, and set errno. - */ -int pfkey_recv_register(int so) -{ - pid_t pid = getpid(); - struct sadb_msg *newmsg; - struct sadb_supported *sup; - caddr_t p; - int tlen; - - /* receive message */ - do { - if ((newmsg = pfkey_recv(so)) == NULL) - return -1; - - } while (newmsg->sadb_msg_type != SADB_REGISTER - || newmsg->sadb_msg_pid != pid); - - /* check and fix */ - newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len); - - tlen = newmsg->sadb_msg_len - sizeof(struct sadb_msg); - p = (caddr_t)newmsg + sizeof(struct sadb_msg); - while (tlen > 0) { - sup = (struct sadb_supported *)p; - switch (sup->sadb_supported_exttype) { - case SADB_EXT_SUPPORTED_AUTH: - case SADB_EXT_SUPPORTED_ENCRYPT: - sup->sadb_supported_len = - PFKEY_UNUNIT64(sup->sadb_supported_len); - break; - default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; - free(newmsg); - return -1; - } - - tlen -= sup->sadb_supported_len; - p += sup->sadb_supported_len; - } - - if (tlen < 0) { - ipsec_errcode = EIPSEC_INVAL_SATYPE; - return -1; - } - - if (ipsec_supported != NULL) - free(ipsec_supported); - - ipsec_supported = newmsg; - - ipsec_errcode = EIPSEC_NO_ERROR; - return 0; -} - -/* - * sending SADB_FLUSH message to the kernel. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_flush(int so, u_int satype) -{ - int len; - - if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0) - return -1; - - return len; -} - -/* - * sending SADB_DUMP message to the kernel. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - */ -int pfkey_send_dump(int so, u_int satype) -{ - int len; - - if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0) - return -1; - - return len; -} - -/* - * sending SADB_X_PROMISC message to the kernel. - * NOTE that this function handles promisc mode toggle only. - * IN: - * flag: set promisc off if zero, set promisc on if non-zero. - * OUT: - * positive: success and return length sent. - * -1 : error occured, and set errno. - * 0 : error occured, and set errno. - - * others: a pointer to new allocated buffer in which supported - * algorithms is. - */ -int pfkey_send_promisc_toggle(int so, int flag) -{ - int len; - - if ((len = pfkey_send_x3(so, SADB_X_PROMISC, (flag ? 1 : 0))) < 0) - return -1; - - return len; -} - -/* sending SADB_ADD or SADB_UPDATE message to the kernel */ -static int pfkey_send_x1( - int so, - u_int type, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, /* upper layer protocol */ - struct sockaddr *proxy, - u_int32_t spi, - caddr_t keymat, - u_int e_type, - u_int e_keylen, - u_int a_type, - u_int a_keylen, - u_int flags, - u_int32_t l_alloc, - u_int32_t l_bytes, - u_int32_t l_addtime, - u_int32_t l_usetime, - u_int32_t seq) -{ - struct sadb_msg *newmsg; - int len; - caddr_t p; - - /* validity check */ - if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return -1; - } - if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; - return -1; - } - if (prefs > _INALENBYAF(src->sa_family) * 8 - || prefd > _INALENBYAF(dst->sa_family) * 8) { - ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; - return -1; - } - - switch (satype) { - case SADB_SATYPE_ESP: - if (e_type == SADB_EALG_NONE) { - ipsec_errcode = EIPSEC_NO_ALGS; - return -1; - } - break; - case SADB_SATYPE_AH: - if (e_type != SADB_EALG_NONE) { - ipsec_errcode = EIPSEC_INVAL_ALGS; - return -1; - } - if (a_type == SADB_AALG_NONE) { - ipsec_errcode = EIPSEC_NO_ALGS; - return -1; - } - break; - case SADB_X_SATYPE_IPCOMP: - break; - default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; - return -1; - } - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_sa) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + sizeof(struct sadb_lifetime) - + sizeof(struct sadb_lifetime); - - if (proxy != NULL) - len += (sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(proxy->sa_family))); - if (e_type != SADB_EALG_NONE) - len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(e_keylen)); - if (a_type != SADB_AALG_NONE) - len += (sizeof(struct sadb_key) + PFKEY_ALIGN8(a_keylen)); - - if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); - return -1; - } - - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = type; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = satype; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_seq = seq; - newmsg->sadb_msg_pid = getpid(); - p = (caddr_t)newmsg + sizeof(*newmsg); - - /* set sadb_sa */ - p = pfkey_setsadbsa(p, (caddr_t)&spi, a_type, e_type, flags); - - /* set sadb_address for source */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, - src->sa_family, - _INADDRBYSA(src), - prefs, - proto, - _INPORTBYSA(src)); - - /* set sadb_address for destination */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, - dst->sa_family, - _INADDRBYSA(dst), - prefd, - proto, - _INPORTBYSA(dst)); - - if (e_type != SADB_EALG_NONE) - p = pfkey_setsadbkey(p, SADB_EXT_KEY_ENCRYPT, - keymat, e_keylen); - if (a_type != SADB_AALG_NONE) - p = pfkey_setsadbkey(p, SADB_EXT_KEY_AUTH, - keymat + e_keylen, a_keylen); - - /* set sadb_address for proxy, if present */ - if (proxy != NULL) - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_PROXY, - proxy->sa_family, - _INADDRBYSA(proxy), - _INALENBYAF(proxy->sa_family) << 3, - 0, - 0); - - /* set sadb_lifetime for destination */ - p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_HARD, - l_alloc, l_bytes, l_addtime, l_usetime); - p = pfkey_setsadblifetime(p, SADB_EXT_LIFETIME_SOFT, - l_alloc, l_bytes, l_addtime, l_usetime); - - /* send message */ - len = pfkey_send(so, newmsg, len); - free(newmsg); - - if (len < 0) - return -1; - - ipsec_errcode = EIPSEC_NO_ERROR; - return len; -} - -/* sending SADB_DELETE or SADB_GET message to the kernel */ -static int pfkey_send_x2( - int so, - u_int type, - u_int satype, - struct sockaddr *src, - u_int prefs, - struct sockaddr *dst, - u_int prefd, - u_int proto, /* upper layer protocol */ - u_int32_t spi) -{ - struct sadb_msg *newmsg; - int len; - caddr_t p; - - /* validity check */ - if (src == NULL || dst == NULL) { - ipsec_errcode = EIPSEC_INVAL_ARGUMENT; - return -1; - } - if (src->sa_family != dst->sa_family) { - ipsec_errcode = EIPSEC_FAMILY_MISMATCH; - return -1; - } - if (prefs > _INALENBYAF(src->sa_family) * 8 - || prefd > _INALENBYAF(dst->sa_family) * 8) { - ipsec_errcode = EIPSEC_INVAL_PREFIXLEN; - return -1; - } - - /* create new sadb_msg to reply. */ - len = sizeof(struct sadb_msg) - + sizeof(struct sadb_sa) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)) - + sizeof(struct sadb_address) - + PFKEY_ALIGN8(_SALENBYAF(src->sa_family)); - - if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); - return -1; - } - - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = type; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = satype; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_seq = 0; - newmsg->sadb_msg_pid = getpid(); - p = (caddr_t)newmsg + sizeof(*newmsg); - - /* set sadb_sa */ - p = pfkey_setsadbsa(p, (caddr_t)&spi, 0, 0, 0); - - /* set sadb_address for source */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_SRC, - src->sa_family, - _INADDRBYSA(src), - prefs, - proto, - _INPORTBYSA(src)); - - /* set sadb_address for destination */ - p = pfkey_setsadbaddr(p, SADB_EXT_ADDRESS_DST, - dst->sa_family, - _INADDRBYSA(dst), - prefd, - proto, - _INPORTBYSA(dst)); - - /* send message */ - len = pfkey_send(so, newmsg, len); - free(newmsg); - - if (len < 0) - return -1; - - ipsec_errcode = EIPSEC_NO_ERROR; - return len; -} - -/* - * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message - * to the kernel - */ -static int pfkey_send_x3(int so, u_int type, u_int satype) -{ - struct sadb_msg *newmsg; - int len; - - /* validity check */ - switch (type) { - case SADB_X_PROMISC: - if (satype != 0 && satype != 1) { - ipsec_errcode = EIPSEC_INVAL_SATYPE; - return -1; - } - break; - default: - switch (satype) { - case SADB_SATYPE_UNSPEC: - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_IPCOMP: - break; - default: - ipsec_errcode = EIPSEC_INVAL_SATYPE; - return -1; - } - } - - /* create new sadb_msg to send. */ + p = (struct sadb_msg *)buf; len = sizeof(struct sadb_msg); - if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) { - ipsec_set_strerror(strerror(errno)); - return -1; - } - - newmsg->sadb_msg_version = PF_KEY_V2; - newmsg->sadb_msg_type = type; - newmsg->sadb_msg_errno = 0; - newmsg->sadb_msg_satype = satype; - newmsg->sadb_msg_len = PFKEY_UNIT64(len); - newmsg->sadb_msg_seq = 0; - newmsg->sadb_msg_pid = getpid(); - - /* send message */ - len = pfkey_send(so, newmsg, len); - free(newmsg); - - if (len < 0) - return -1; - - ipsec_errcode = EIPSEC_NO_ERROR; - return len; -} - -/* - * open a socket. - * OUT: - * -1: fail. - * others : success and return value of socket. - */ -int pfkey_open(void) -{ - int so; - const int bufsiz = 128 * 1024; /*is 128K enough?*/ - - if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) { - ipsec_set_strerror(strerror(errno)); - return -1; - } - - /* - * This is a temporary workaround for KAME PR 154. - * Don't really care even if it fails. - */ - (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF, &bufsiz, sizeof(bufsiz)); - (void)setsockopt(so, SOL_SOCKET, SO_RCVBUF, &bufsiz, sizeof(bufsiz)); - - ipsec_errcode = EIPSEC_NO_ERROR; - return so; -} - -/* - * close a socket. - * OUT: - * 0: success. - * -1: fail. - */ -void pfkey_close(int so) -{ - (void)close(so); - - ipsec_errcode = EIPSEC_NO_ERROR; - return; -} - -/* - * receive sadb_msg data, and return pointer to new buffer allocated. - * Must free this buffer later. - * OUT: - * NULL : error occured. - * others : a pointer to sadb_msg structure. - */ -struct sadb_msg *pfkey_recv(int so) -{ - struct sadb_msg buf, *newmsg; - int len, reallen; - - while ((len = recv(so, (caddr_t)&buf, sizeof(buf), MSG_PEEK)) < 0) { - if (errno == EINTR) continue; - ipsec_set_strerror(strerror(errno)); - return NULL; - } - - if (len < sizeof(buf)) { - recv(so, (caddr_t)&buf, sizeof(buf), 0); - ipsec_errcode = EIPSEC_MAX; - return NULL; - } - - /* read real message */ - reallen = PFKEY_UNUNIT64(buf.sadb_msg_len); - if ((newmsg = CALLOC(reallen, struct sadb_msg *)) == 0) { - ipsec_set_strerror(strerror(errno)); - return NULL; - } - - while ((len = recv(so, (caddr_t)newmsg, reallen, 0)) < 0) { - if (errno == EINTR) continue; - ipsec_set_strerror(strerror(errno)); - free(newmsg); - return NULL; - } - - if (len != reallen) { - ipsec_errcode = EIPSEC_MAX; - free(newmsg); - return NULL; - } - - ipsec_errcode = EIPSEC_NO_ERROR; - return newmsg; -} - -/* - * send message to a socket. - * OUT: - * others: success and return length sent. - * -1 : fail. - */ -int pfkey_send(int so, struct sadb_msg *msg, int len) -{ - if ((len = send(so, (caddr_t)msg, len, 0)) < 0) { - ipsec_set_strerror(strerror(errno)); - return -1; - } - - ipsec_errcode = EIPSEC_NO_ERROR; - return len; -} - -/* %%% */ -/* - * set sadb_address structure after clearing buffer with zero. - * OUT: the pointer of buf + len. - */ -static caddr_t pfkey_setsadbaddr(caddr_t buf, u_int type, - u_int family, caddr_t addr, - u_int pref, u_int proto, u_int port) -{ - caddr_t p = buf; /* save */ - int len; - - len = sizeof(struct sadb_address) + PFKEY_ALIGN8(_SALENBYAF(family)); memset(p, 0, len); + p->sadb_msg_version = PF_KEY_V2; + p->sadb_msg_type = type; + p->sadb_msg_errno = 0; + p->sadb_msg_satype = satype; + p->sadb_msg_len = PFKEY_UNIT64(tlen); + p->sadb_msg_mode = mode; + p->sadb_msg_reserved1 = 0; + p->sadb_msg_seq = seq; + p->sadb_msg_pid = (u_int32_t)pid; + p->sadb_msg_reqid = reqid; + p->sadb_msg_reserved2 = 0; -#define _SADB_ADDRESS(p) ((struct sadb_address *)(p)) - _SADB_ADDRESS(p)->sadb_address_len = PFKEY_UNIT64(len); - _SADB_ADDRESS(p)->sadb_address_exttype = type; - _SADB_ADDRESS(p)->sadb_address_proto = proto; - _SADB_ADDRESS(p)->sadb_address_prefixlen = pref; -#undef _SADB_ADDRESS(p) - p += sizeof(struct sadb_address); + return(buf + len); +} - ((struct sockaddr *)p)->sa_len = _SALENBYAF(family); - ((struct sockaddr *)p)->sa_family = family; - switch (family) { - case AF_INET: - ((struct sockaddr_in *)p)->sin_port = port; - break; -#ifdef INET6 - case AF_INET6: - ((struct sockaddr_in6 *)p)->sin6_port = port; - break; -#endif - } - memcpy(_INADDRBYSA(p), addr, _INALENBYAF(family)); +/* + * copy secasvar data into sadb_address. + * `buf' must has been allocated sufficiently. + */ +static caddr_t +pfkey_setsadbsa(buf, spi, wsize, auth, enc, flags) + caddr_t buf; + u_int32_t spi, flags; + u_int wsize, auth, enc; +{ + struct sadb_sa *p; + u_int len; - return buf + len; + p = (struct sadb_sa *)buf; + len = sizeof(struct sadb_sa); + + memset(p, 0, len); + p->sadb_sa_len = PFKEY_UNIT64(len); + p->sadb_sa_exttype = SADB_EXT_SA; + p->sadb_sa_spi = spi; + p->sadb_sa_replay = wsize; + p->sadb_sa_state = SADB_SASTATE_LARVAL; + p->sadb_sa_auth = auth; + p->sadb_sa_encrypt = enc; + p->sadb_sa_flags = flags; + + return(buf + len); +} + +/* + * set data into sadb_address. + * `buf' must has been allocated sufficiently. + * prefixlen is in bits. + */ +static caddr_t +pfkey_setsadbaddr(buf, exttype, saddr, prefixlen, ul_proto) + caddr_t buf; + u_int exttype; + struct sockaddr *saddr; + u_int prefixlen; + u_int ul_proto; +{ + struct sadb_address *p; + u_int len; + + p = (struct sadb_address *)buf; + len = sizeof(struct sadb_address) + PFKEY_ALIGN8(saddr->sa_len); + + memset(p, 0, len); + p->sadb_address_len = PFKEY_UNIT64(len); + p->sadb_address_exttype = exttype & 0xffff; + p->sadb_address_proto = ul_proto & 0xff; + p->sadb_address_prefixlen = prefixlen; + p->sadb_address_reserved = 0; + + memcpy(p + 1, saddr, saddr->sa_len); + + return(buf + len); } /* * set sadb_key structure after clearing buffer with zero. * OUT: the pointer of buf + len. */ -static caddr_t pfkey_setsadbkey(caddr_t buf, u_int type, - caddr_t key, u_int keylen) +static caddr_t +pfkey_setsadbkey(buf, type, key, keylen) + caddr_t buf, key; + u_int type, keylen; { - caddr_t p = buf; /* save */ - int len, aligned_len; + struct sadb_key *p; + u_int len; + + p = (struct sadb_key *)buf; + len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen); - aligned_len = PFKEY_ALIGN8(keylen); - len = sizeof(struct sadb_key) + aligned_len; memset(p, 0, len); + p->sadb_key_len = PFKEY_UNIT64(len); + p->sadb_key_exttype = type; + p->sadb_key_bits = keylen << 3; + p->sadb_key_reserved = 0; -#define _SADB_KEY(p) ((struct sadb_key *)(p)) - _SADB_KEY(p)->sadb_key_len = PFKEY_UNIT64(len); - _SADB_KEY(p)->sadb_key_exttype = type; - _SADB_KEY(p)->sadb_key_bits = keylen << 3; - _SADB_KEY(p)->sadb_key_reserved = 0; -#undef _SADB_KEY(p) - p += sizeof(struct sadb_key); - - memcpy(p, key, keylen); - p += aligned_len; - - return buf + len; -} - -/* - * set sadb_sa structure after clearing buffer with zero. - * OUT: the pointer of buf + len. - */ -static caddr_t pfkey_setsadbsa(caddr_t buf, caddr_t spi, - u_int a_type, u_int e_type, u_int flags) -{ - caddr_t p = buf; - int len; - - len = sizeof(struct sadb_sa); - memset(p, 0, len); - -#define _SADB_SA(p) ((struct sadb_sa *)(p)) - _SADB_SA(p)->sadb_sa_len = PFKEY_UNIT64(len); - _SADB_SA(p)->sadb_sa_exttype = SADB_EXT_SA; - memcpy(&_SADB_SA(p)->sadb_sa_spi, spi, PFKEY_SPI_SIZE); - _SADB_SA(p)->sadb_sa_replay = 0; - _SADB_SA(p)->sadb_sa_state = 0; - _SADB_SA(p)->sadb_sa_auth = a_type; - _SADB_SA(p)->sadb_sa_encrypt = e_type; - _SADB_SA(p)->sadb_sa_flags = flags; -#undef _SADB_SA(p) + memcpy(p + 1, key, keylen); return buf + len; } @@ -1236,39 +1384,40 @@ static caddr_t pfkey_setsadbsa(caddr_t buf, caddr_t spi, * set sadb_lifetime structure after clearing buffer with zero. * OUT: the pointer of buf + len. */ -static caddr_t pfkey_setsadblifetime(caddr_t buf, u_int type, - u_int32_t l_alloc, u_int32_t l_bytes, - u_int32_t l_addtime, u_int32_t l_usetime) +static caddr_t +pfkey_setsadblifetime(buf, type, l_alloc, l_bytes, l_addtime, l_usetime) + caddr_t buf; + u_int type; + u_int32_t l_alloc, l_bytes, l_addtime, l_usetime; { - caddr_t p = buf; - int len; + struct sadb_lifetime *p; + u_int len; + p = (struct sadb_lifetime *)buf; len = sizeof(struct sadb_lifetime); - memset(p, 0, len); -#define _SADB_LIFETIME(p) ((struct sadb_lifetime *)(p)) - _SADB_LIFETIME(p)->sadb_lifetime_len = PFKEY_UNIT64(len); - _SADB_LIFETIME(p)->sadb_lifetime_exttype = type; + memset(p, 0, len); + p->sadb_lifetime_len = PFKEY_UNIT64(len); + p->sadb_lifetime_exttype = type; switch (type) { case SADB_EXT_LIFETIME_SOFT: - _SADB_LIFETIME(p)->sadb_lifetime_allocations + p->sadb_lifetime_allocations = (l_alloc * soft_lifetime_allocations_rate) /100; - _SADB_LIFETIME(p)->sadb_lifetime_bytes - = ((l_bytes * soft_lifetime_bytes_rate) /100) << 10; - _SADB_LIFETIME(p)->sadb_lifetime_addtime + p->sadb_lifetime_bytes + = (l_bytes * soft_lifetime_bytes_rate) /100; + p->sadb_lifetime_addtime = (l_addtime * soft_lifetime_addtime_rate) /100; - _SADB_LIFETIME(p)->sadb_lifetime_usetime + p->sadb_lifetime_usetime = (l_usetime * soft_lifetime_usetime_rate) /100; break; case SADB_EXT_LIFETIME_HARD: - _SADB_LIFETIME(p)->sadb_lifetime_allocations = l_alloc; - _SADB_LIFETIME(p)->sadb_lifetime_bytes = l_bytes << 10; - _SADB_LIFETIME(p)->sadb_lifetime_addtime = l_addtime; - _SADB_LIFETIME(p)->sadb_lifetime_usetime = l_usetime; + p->sadb_lifetime_allocations = l_alloc; + p->sadb_lifetime_bytes = l_bytes; + p->sadb_lifetime_addtime = l_addtime; + p->sadb_lifetime_usetime = l_usetime; break; } -#undef _SADB_LIFETIME(p) return buf + len; } diff --git a/lib/libipsec/pfkey_dump.c b/lib/libipsec/pfkey_dump.c index 930afcd435ba..f321dd12dd6e 100644 --- a/lib/libipsec/pfkey_dump.c +++ b/lib/libipsec/pfkey_dump.c @@ -1,4 +1,4 @@ -/* $NetBSD: pfkey_dump.c,v 1.3 1999/07/04 01:36:13 itojun Exp $ */ +/* $NetBSD: pfkey_dump.c,v 1.4 2000/01/31 14:15:32 itojun Exp $ */ /* * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project. @@ -38,6 +38,7 @@ #include #include +#include #ifdef INET6 #include #endif @@ -52,7 +53,7 @@ #include "ipsec_strerror.h" #define GETMSGSTR(str, num) \ -{ \ +do { \ if (sizeof((str)[0]) == 0 \ || num >= sizeof(str)/sizeof((str)[0])) \ printf("%d ", (num)); \ @@ -60,14 +61,15 @@ printf("%d ", (num)); \ else \ printf("%s ", (str)[(num)]); \ -} +} while (0) #define GETAF(p) \ (((struct sockaddr *)(p))->sa_family) -static char *_str_addr(u_int family, caddr_t addr, u_int pref, u_int port); -static char *_str_time(time_t t); -static void _str_lifetime_byte(struct sadb_lifetime *x, char *str); +static char *_str_ipaddr __P((u_int family, caddr_t addr)); +static char *_str_prefport __P((u_int family, u_int pref, u_int port)); +static char *_str_time __P((time_t t)); +static void _str_lifetime_byte __P((struct sadb_lifetime *x, char *str)); /* * Must to be re-written about following strings. @@ -85,21 +87,27 @@ static char *_str_satype[] = { "ipcomp", }; -static char *_str_upper[] = { - "any", "icmp", "", "", "", - "", "tcp", "", "", "", - "", "", "", "", "", - "", "", "udp", "", "", - "", "", "", "", "", - "", "", "", "", "", +static char *_str_mode[] = { + "any", + "transport", + "tunnel", }; -#if 0 -static char *_str_base[] = { - "new", - "old", +static char *_str_upper[] = { +/*0*/ "ip", "icmp", "igmp", "ggp", "ip4", + "", "tcp", "", "egp", "", +/*10*/ "", "", "", "", "", + "", "", "udp", "", "", +/*20*/ "", "", "idp", "", "", + "", "", "", "", "tp", +/*30*/ "", "", "", "", "", + "", "", "", "", "", +/*40*/ "", "ip6", "", "rt6", "frag6", + "", "rsvp", "gre", "", "", +/*50*/ "esp", "ah", "", "", "", + "", "", "", "icmp6", "none", +/*60*/ "dst6", }; -#endif static char *_str_state[] = { "larval", @@ -134,16 +142,12 @@ static char *_str_alg_comp[] = { "lzs", }; -static char *_str_dir[] = { - "outbound", - "inbound", - "bi-direction", -}; - /* * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). */ -void pfkey_sadump(struct sadb_msg *m) +void +pfkey_sadump(m) + struct sadb_msg *m; { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_sa *m_sa; @@ -154,7 +158,11 @@ void pfkey_sadump(struct sadb_msg *m) struct sadb_sens *m_sens; /* check pfkey message. */ - if (pfkey_check(m, mhp)) { + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } @@ -169,7 +177,7 @@ void pfkey_sadump(struct sadb_msg *m) m_auth = (struct sadb_key *)mhp[SADB_EXT_KEY_AUTH]; m_enc = (struct sadb_key *)mhp[SADB_EXT_KEY_ENCRYPT]; m_sid = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; - m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_SRC]; + m_did = (struct sadb_ident *)mhp[SADB_EXT_IDENTITY_DST]; m_sens = (struct sadb_sens *)mhp[SADB_EXT_SENSITIVITY]; /* source address */ @@ -178,10 +186,7 @@ void pfkey_sadump(struct sadb_msg *m) return; } printf("%s ", - _str_addr(GETAF((caddr_t)m_saddr + sizeof(*m_saddr)), - _INADDRBYSA((caddr_t)m_saddr + sizeof(*m_saddr)), - m_saddr->sadb_address_prefixlen, - _INPORTBYSA((caddr_t)m_saddr + sizeof(*m_saddr)))); + _str_ipaddr(GETAF(m_saddr + 1), _INADDRBYSA(m_saddr + 1))); /* destination address */ if (m_daddr == NULL) { @@ -189,42 +194,25 @@ void pfkey_sadump(struct sadb_msg *m) return; } printf("%s ", - _str_addr(GETAF((caddr_t)m_daddr + sizeof(*m_daddr)), - _INADDRBYSA((caddr_t)m_daddr + sizeof(*m_daddr)), - m_daddr->sadb_address_prefixlen, - _INPORTBYSA((caddr_t)m_daddr + sizeof(*m_daddr)))); - - /* upper layer protocol */ - if (m_saddr->sadb_address_proto != m_saddr->sadb_address_proto) { - printf("upper layer protocol mismatched.\n"); - return; - } - GETMSGSTR(_str_upper, m_saddr->sadb_address_proto); - - /* proxy address */ - if (m_paddr != NULL) { - int prefix = _INALENBYAF(GETAF((caddr_t)m_paddr + sizeof(*m_paddr))) << 3; - printf("%s", - _str_addr(GETAF((caddr_t)m_paddr + sizeof(*m_paddr)), - _INADDRBYSA((caddr_t)m_paddr + sizeof(*m_paddr)), - prefix, - 0)); - } - printf("\n"); + _str_ipaddr(GETAF(m_daddr + 1), _INADDRBYSA(m_daddr + 1))); /* SA type */ if (m_sa == NULL) { printf("no SA extension.\n"); return; } - printf("\t"); + printf("\n\t"); + GETMSGSTR(_str_satype, m->sadb_msg_satype); - printf("spi=%u(0x%08x) replay=%u flags=0x%08x\n", + printf("mode="); + GETMSGSTR(_str_mode, m->sadb_msg_mode); + + printf("spi=%u(0x%08x) reqid=%u(0x%08x)\n", (u_int32_t)ntohl(m_sa->sadb_sa_spi), (u_int32_t)ntohl(m_sa->sadb_sa_spi), - m_sa->sadb_sa_replay, - m_sa->sadb_sa_flags); + (u_int32_t)m->sadb_msg_reqid, + (u_int32_t)m->sadb_msg_reqid); /* encryption key */ if (m->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { @@ -249,8 +237,13 @@ void pfkey_sadump(struct sadb_msg *m) printf("\n"); } + /* replay windoe size & flags */ + printf("\treplay=%u flags=0x%08x ", + m_sa->sadb_sa_replay, + m_sa->sadb_sa_flags); + /* state */ - printf("\tstate="); + printf("state="); GETMSGSTR(_str_state, m_sa->sadb_sa_state); printf("seq=%lu pid=%lu\n", @@ -299,24 +292,26 @@ void pfkey_sadump(struct sadb_msg *m) 0 : m_lfts->sadb_lifetime_allocations)); } - { /* XXX TEST */ - char *x = (char *)&m->sadb_msg_reserved; - printf("\tdir="); - GETMSGSTR(_str_dir, (int)x[0]); - printf("refcnt=%d\n", (int)x[1]); - } + /* XXX DEBUG */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved2); return; } -void pfkey_spdump(struct sadb_msg *m) +void +pfkey_spdump(m) + struct sadb_msg *m; { caddr_t mhp[SADB_EXT_MAX + 1]; struct sadb_address *m_saddr, *m_daddr; struct sadb_x_policy *m_xpl; /* check pfkey message. */ - if (pfkey_check(m, mhp)) { + if (pfkey_align(m, mhp)) { + printf("%s\n", ipsec_strerror()); + return; + } + if (pfkey_check(mhp)) { printf("%s\n", ipsec_strerror()); return; } @@ -330,25 +325,32 @@ void pfkey_spdump(struct sadb_msg *m) printf("no ADDRESS_SRC extension.\n"); return; } - printf("%s ", - _str_addr(GETAF((caddr_t)m_saddr + sizeof(*m_saddr)), - _INADDRBYSA((caddr_t)m_saddr + sizeof(*m_saddr)), - m_saddr->sadb_address_prefixlen, - _INPORTBYSA((caddr_t)m_saddr + sizeof(*m_saddr)))); + printf("%s%s ", + _str_ipaddr(GETAF(m_saddr + 1), _INADDRBYSA(m_saddr + 1)), + _str_prefport(GETAF(m_saddr + 1), + m_saddr->sadb_address_prefixlen, + _INPORTBYSA(m_saddr + 1))); /* destination address */ if (m_daddr == NULL) { printf("no ADDRESS_DST extension.\n"); return; } - printf("%s ", - _str_addr(GETAF((caddr_t)m_daddr + sizeof(*m_daddr)), - _INADDRBYSA((caddr_t)m_daddr + sizeof(*m_daddr)), - m_daddr->sadb_address_prefixlen, - _INPORTBYSA((caddr_t)m_daddr + sizeof(*m_daddr)))); + printf("%s%s ", + _str_ipaddr(GETAF(m_daddr + 1), _INADDRBYSA(m_daddr + 1)), + _str_prefport(GETAF(m_daddr + 1), + m_daddr->sadb_address_prefixlen, + _INPORTBYSA(m_daddr + 1))); /* upper layer protocol */ - GETMSGSTR(_str_upper, m_saddr->sadb_address_proto); + if (m_saddr->sadb_address_proto != m_daddr->sadb_address_proto) { + printf("upper layer protocol mismatched.\n"); + return; + } + if (m_saddr->sadb_address_proto == IPSEC_ULPROTO_ANY) + printf("any"); + else + GETMSGSTR(_str_upper, m_saddr->sadb_address_proto); /* policy */ { @@ -369,37 +371,65 @@ void pfkey_spdump(struct sadb_msg *m) (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); - { /* TEST */ - char *x = (char *)&m->sadb_msg_reserved; - printf("\tdir="); - GETMSGSTR(_str_dir, (int)x[0]); - printf("refcnt=%d\n", (int)x[1]); - } + /* XXX TEST */ + printf("\trefcnt=%u\n", m->sadb_msg_reserved2); return; } /* - * set "ip address/prefix[port number]" to buffer. + * set "ipaddress" to buffer. */ -static char *_str_addr(u_int family, caddr_t addr, u_int pref, u_int port) +static char * +_str_ipaddr(family, addr) + u_int family; + caddr_t addr; { static char buf[128]; - char pbuf[128]; + char addrbuf[128]; if (addr == NULL) return ""; - inet_ntop(family, addr, pbuf, sizeof(pbuf)); + inet_ntop(family, addr, addrbuf, sizeof(addrbuf)); + + snprintf(buf, sizeof(buf), "%s", addrbuf); + + return buf; +} + +/* + * set "/prefix[port number]" to buffer. + */ +static char * +_str_prefport(family, pref, port) + u_int family, pref, port; +{ + static char buf[128]; + char prefbuf[10]; + char portbuf[10]; + + if (pref == (_INALENBYAF(family) << 3)) + prefbuf[0] = '\0'; + else + snprintf(prefbuf, sizeof(prefbuf), "/%u", pref); + + if (port == IPSEC_PORT_ANY) + snprintf(portbuf, sizeof(portbuf), "[%s]", "any"); + else + snprintf(portbuf, sizeof(portbuf), "[%u]", ntohs(port)); + + snprintf(buf, sizeof(buf), "%s%s", prefbuf, portbuf); - snprintf(buf, sizeof(buf), "%s/%u[%u]", pbuf, pref, ntohs(port)); return buf; } /* * set "Mon Day Time Year" to buffer */ -static char *_str_time(time_t t) +static char * +_str_time(t) + time_t t; { static char buf[128]; @@ -417,7 +447,10 @@ static char *_str_time(time_t t) return(buf); } -static void _str_lifetime_byte(struct sadb_lifetime *x, char *str) +static void +_str_lifetime_byte(x, str) + struct sadb_lifetime *x; + char *str; { double y; char *unit; diff --git a/lib/libipsec/shlib_version b/lib/libipsec/shlib_version index 7d7ac3e46bbc..5450fc6334a6 100644 --- a/lib/libipsec/shlib_version +++ b/lib/libipsec/shlib_version @@ -1,5 +1,5 @@ -# $NetBSD: shlib_version,v 1.1 1999/07/01 20:15:29 itojun Exp $ +# $NetBSD: shlib_version,v 1.2 2000/01/31 14:15:32 itojun Exp $ # Remember to update distrib/sets/lists/base/shl.* when changing # -major=0 +major=1 minor=0