From owner-svn-src-all@freebsd.org Tue Mar 7 00:13:55 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 6F4AECFA030; Tue, 7 Mar 2017 00:13:55 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 3E0EC16AC; Tue, 7 Mar 2017 00:13:55 +0000 (UTC) (envelope-from ae@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v270DsI1039322; Tue, 7 Mar 2017 00:13:54 GMT (envelope-from ae@FreeBSD.org) Received: (from ae@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v270DrDf039314; Tue, 7 Mar 2017 00:13:53 GMT (envelope-from ae@FreeBSD.org) Message-Id: <201703070013.v270DrDf039314@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: ae set sender to ae@FreeBSD.org using -f From: "Andrey V. Elsukov" Date: Tue, 7 Mar 2017 00:13:53 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r314812 - in head: lib/libipsec sbin/setkey sys/net sys/netipsec X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 07 Mar 2017 00:13:55 -0000 Author: ae Date: Tue Mar 7 00:13:53 2017 New Revision: 314812 URL: https://svnweb.freebsd.org/changeset/base/314812 Log: Introduce the concept of IPsec security policies scope. Currently are defined three scopes: global, ifnet, and pcb. Generic security policies that IKE daemon can add via PF_KEY interface or an administrator creates with setkey(8) utility have GLOBAL scope. Such policies can be applied by the kernel to outgoing packets and checked agains inbound packets after IPsec processing. Security policies created by if_ipsec(4) interfaces have IFNET scope. Such policies are applied to packets that are passed through if_ipsec(4) interface. And security policies created by application using setsockopt() IP_IPSEC_POLICY option have PCB scope. Such policies are applied to packets related to specific socket. Currently there is no way to list PCB policies via setkey(8) utility. Modify setkey(8) and libipsec(3) to be able distinguish the scope of security policies in the `setkey -DP` listing. Add two optional flags: '-t' to list only policies related to virtual *tunneling* interfaces, i.e. policies with IFNET scope, and '-g' to list only policies with GLOBAL scope. By default policies from all scopes are listed. To implement this PF_KEY's sadb_x_policy structure was modified. sadb_x_policy_reserved field is used to pass the policy scope from the kernel to userland. SADB_SPDDUMP message extended to support filtering by scope: sadb_msg_satype field is used to specify bit mask of requested scopes. For IFNET policies the sadb_x_policy_priority field of struct sadb_x_policy is used to pass if_ipsec's interface if_index to the userland. For GLOBAL policies sadb_x_policy_priority is used only to manage order of security policies in the SPDB. For IFNET policies it is not used, so it can be used to keep if_index. After this change the output of `setkey -DP` now looks like: # setkey -DPt 0.0.0.0/0[any] 0.0.0.0/0[any] any in ipsec esp/tunnel/87.250.242.144-87.250.242.145/unique:145 spid=7 seq=3 pid=58025 scope=ifnet ifname=ipsec0 refcnt=1 # setkey -DPg ::/0 ::/0 icmp6 135,0 out none spid=5 seq=1 pid=872 scope=global refcnt=1 No objection from: #network Obtained from: Yandex LLC MFC after: 2 weeks Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D9805 Modified: head/lib/libipsec/pfkey_dump.c head/sbin/setkey/setkey.8 head/sbin/setkey/setkey.c head/sys/net/if_ipsec.c head/sys/net/pfkeyv2.h head/sys/netipsec/ipsec.h head/sys/netipsec/key.c Modified: head/lib/libipsec/pfkey_dump.c ============================================================================== --- head/lib/libipsec/pfkey_dump.c Mon Mar 6 23:47:59 2017 (r314811) +++ head/lib/libipsec/pfkey_dump.c Tue Mar 7 00:13:53 2017 (r314812) @@ -35,8 +35,9 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include +#include #include +#include #include #include @@ -204,6 +205,13 @@ static struct val2str str_alg_comp[] = { { -1, NULL, }, }; +static struct val2str str_sp_scope[] = { + { IPSEC_POLICYSCOPE_GLOBAL, "global" }, + { IPSEC_POLICYSCOPE_IFNET, "ifnet" }, + { IPSEC_POLICYSCOPE_PCB, "pcb"}, + { -1, NULL }, +}; + /* * dump SADB_MSG formated. For debugging, you should use kdebug_sadb(). */ @@ -398,8 +406,7 @@ pfkey_sadump(m) } void -pfkey_spdump(m) - struct sadb_msg *m; +pfkey_spdump(struct sadb_msg *m) { char pbuf[NI_MAXSERV]; caddr_t mhp[SADB_EXT_MAX + 1]; @@ -507,10 +514,15 @@ pfkey_spdump(m) } - printf("\tspid=%ld seq=%ld pid=%ld\n", + printf("\tspid=%ld seq=%ld pid=%ld scope=", (u_long)m_xpl->sadb_x_policy_id, (u_long)m->sadb_msg_seq, (u_long)m->sadb_msg_pid); + GETMSGV2S(str_sp_scope, m_xpl->sadb_x_policy_scope); + if (m_xpl->sadb_x_policy_scope == IPSEC_POLICYSCOPE_IFNET && + if_indextoname(m_xpl->sadb_x_policy_ifindex, pbuf) != NULL) + printf("ifname=%s", pbuf); + printf("\n"); /* XXX TEST */ printf("\trefcnt=%u\n", m->sadb_msg_reserved); Modified: head/sbin/setkey/setkey.8 ============================================================================== --- head/sbin/setkey/setkey.8 Mon Mar 6 23:47:59 2017 (r314811) +++ head/sbin/setkey/setkey.8 Tue Mar 7 00:13:53 2017 (r314812) @@ -29,7 +29,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 27, 2017 +.Dd March 7, 2017 .Dt SETKEY 8 .Os .\" @@ -45,7 +45,7 @@ .Op Fl v .Fl f Ar filename .Nm -.Op Fl aPlv +.Op Fl Pgltv .Fl D .Nm .Op Fl Pv @@ -81,18 +81,21 @@ Flush the SAD entries. If with .Fl P , the SPD entries are flushed. -.It Fl a -The -.Nm -utility -usually does not display dead SAD entries with -.Fl D . -If with -.Fl a , -the dead SAD entries will be displayed as well. -A dead SAD entry means that -it has been expired but remains in the system -because it is referenced by some SPD entries. +.It Fl g +Only SPD entries with global scope are dumped with +.Fl D +and +.Fl P +flags. +.It Fl t +Only SPD entries with ifnet scope are dumped with +.Fl D +and +.Fl P +flags. +Such SPD entries are linked to the corresponding +.Xr if_ipsec 4 +virtual tunneling interface. .It Fl h Add hexadecimal dump on .Fl x @@ -697,6 +700,7 @@ add 10.1.10.34 10.1.10.36 tcp 0x1000 -A .\" .Sh SEE ALSO .Xr ipsec_set_policy 3 , +.Xr if_ipsec 4 , .Xr racoon 8 , .Xr sysctl 8 .Rs Modified: head/sbin/setkey/setkey.c ============================================================================== --- head/sbin/setkey/setkey.c Mon Mar 6 23:47:59 2017 (r314811) +++ head/sbin/setkey/setkey.c Tue Mar 7 00:13:53 2017 (r314812) @@ -56,7 +56,7 @@ void usage(void); int main(int, char **); int get_supported(void); -void sendkeyshort(u_int); +void sendkeyshort(u_int, uint8_t); void promisc(void); int sendkeymsg(char *, size_t); int postproc(struct sadb_msg *, int); @@ -81,6 +81,7 @@ int f_cmddump = 0; int f_policy = 0; int f_hexdump = 0; int f_tflag = 0; +int f_scope = 0; static time_t thiszone; extern int lineno; @@ -93,7 +94,7 @@ usage() printf("usage: setkey [-v] -c\n"); printf(" setkey [-v] -f filename\n"); - printf(" setkey [-Palv] -D\n"); + printf(" setkey [-Pagltv] -D\n"); printf(" setkey [-Pv] -F\n"); printf(" setkey [-h] -x\n"); exit(1); @@ -114,7 +115,7 @@ main(ac, av) thiszone = gmt2local(0); - while ((c = getopt(ac, av, "acdf:hlvxDFP")) != -1) { + while ((c = getopt(ac, av, "acdf:ghltvxDFP")) != -1) { switch (c) { case 'c': f_mode = MODE_SCRIPT; @@ -149,6 +150,12 @@ main(ac, av) case 'P': f_policy = 1; break; + case 'g': /* global */ + f_scope |= IPSEC_POLICYSCOPE_GLOBAL; + break; + case 't': /* tunnel */ + f_scope |= IPSEC_POLICYSCOPE_IFNET; + break; case 'v': f_verbose = 1; break; @@ -166,10 +173,12 @@ main(ac, av) switch (f_mode) { case MODE_CMDDUMP: - sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP); + sendkeyshort(f_policy ? SADB_X_SPDDUMP: SADB_DUMP, + f_policy ? f_scope: SADB_SATYPE_UNSPEC); break; case MODE_CMDFLUSH: - sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH); + sendkeyshort(f_policy ? SADB_X_SPDFLUSH: SADB_FLUSH, + SADB_SATYPE_UNSPEC); break; case MODE_SCRIPT: if (get_supported() < 0) { @@ -204,15 +213,14 @@ get_supported() } void -sendkeyshort(type) - u_int type; +sendkeyshort(u_int type, uint8_t satype) { struct sadb_msg msg; msg.sadb_msg_version = PF_KEY_V2; msg.sadb_msg_type = type; msg.sadb_msg_errno = 0; - msg.sadb_msg_satype = SADB_SATYPE_UNSPEC; + msg.sadb_msg_satype = satype; msg.sadb_msg_len = PFKEY_UNIT64(sizeof(msg)); msg.sadb_msg_reserved = 0; msg.sadb_msg_seq = 0; Modified: head/sys/net/if_ipsec.c ============================================================================== --- head/sys/net/if_ipsec.c Mon Mar 6 23:47:59 2017 (r314811) +++ head/sys/net/if_ipsec.c Tue Mar 7 00:13:53 2017 (r314812) @@ -717,7 +717,7 @@ bad: * ipsec esp/tunnel/LocalIP-RemoteIP/unique:reqid */ static int -ipsec_newpolicies(struct secpolicy *sp[IPSEC_SPCOUNT], +ipsec_newpolicies(struct ipsec_softc *sc, struct secpolicy *sp[IPSEC_SPCOUNT], const struct sockaddr *src, const struct sockaddr *dst, uint32_t reqid) { struct ipsecrequest *isr; @@ -734,6 +734,8 @@ ipsec_newpolicies(struct secpolicy *sp[I sp[i]->state = IPSEC_SPSTATE_DEAD; sp[i]->req[sp[i]->tcount++] = isr; sp[i]->created = time_second; + /* Use priority field to store if_index */ + sp[i]->priority = sc->ifp->if_index; isr->level = IPSEC_LEVEL_UNIQUE; isr->saidx.proto = IPPROTO_ESP; isr->saidx.mode = IPSEC_MODE_TUNNEL; @@ -936,7 +938,7 @@ ipsec_set_tunnel(struct ipsec_softc *sc, sx_assert(&ipsec_ioctl_sx, SA_XLOCKED); /* Allocate SP with new addresses. */ - if (ipsec_newpolicies(sp, src, dst, reqid) == 0) { + if (ipsec_newpolicies(sc, sp, src, dst, reqid) == 0) { /* Add new policies to SPDB */ if (key_register_ifnet(sp, IPSEC_SPCOUNT) != 0) { for (i = 0; i < IPSEC_SPCOUNT; i++) Modified: head/sys/net/pfkeyv2.h ============================================================================== --- head/sys/net/pfkeyv2.h Mon Mar 6 23:47:59 2017 (r314811) +++ head/sys/net/pfkeyv2.h Tue Mar 7 00:13:53 2017 (r314812) @@ -223,9 +223,12 @@ struct sadb_x_policy { u_int16_t sadb_x_policy_exttype; u_int16_t sadb_x_policy_type; /* See policy type of ipsec.h */ u_int8_t sadb_x_policy_dir; /* direction, see ipsec.h */ - u_int8_t sadb_x_policy_reserved; + u_int8_t sadb_x_policy_scope; /* scope, see ipsec.h */ u_int32_t sadb_x_policy_id; u_int32_t sadb_x_policy_priority; +#define sadb_x_policy_reserved sadb_x_policy_scope +/* Policy with ifnet scope uses priority field to store ifindex */ +#define sadb_x_policy_ifindex sadb_x_policy_priority }; _Static_assert(sizeof(struct sadb_x_policy) == 16, "struct size mismatch"); Modified: head/sys/netipsec/ipsec.h ============================================================================== --- head/sys/netipsec/ipsec.h Mon Mar 6 23:47:59 2017 (r314811) +++ head/sys/netipsec/ipsec.h Tue Mar 7 00:13:53 2017 (r314812) @@ -179,6 +179,12 @@ struct secspacq { #define IPSEC_POLICY_ENTRUST 3 /* consulting SPD if present. */ #define IPSEC_POLICY_BYPASS 4 /* only for privileged socket. */ +/* Policy scope */ +#define IPSEC_POLICYSCOPE_ANY 0x00 /* unspecified */ +#define IPSEC_POLICYSCOPE_GLOBAL 0x01 /* global scope */ +#define IPSEC_POLICYSCOPE_IFNET 0x02 /* if_ipsec(4) scope */ +#define IPSEC_POLICYSCOPE_PCB 0x04 /* PCB scope */ + /* Security protocol level */ #define IPSEC_LEVEL_DEFAULT 0 /* reference to system default */ #define IPSEC_LEVEL_USE 1 /* use SA if present. */ Modified: head/sys/netipsec/key.c ============================================================================== --- head/sys/netipsec/key.c Mon Mar 6 23:47:59 2017 (r314811) +++ head/sys/netipsec/key.c Tue Mar 7 00:13:53 2017 (r314812) @@ -1660,6 +1660,16 @@ key_sp2msg(struct secpolicy *sp, void *r xpl->sadb_x_policy_dir = sp->spidx.dir; xpl->sadb_x_policy_id = sp->id; xpl->sadb_x_policy_priority = sp->priority; + switch (sp->state) { + case IPSEC_SPSTATE_IFNET: + xpl->sadb_x_policy_scope = IPSEC_POLICYSCOPE_IFNET; + break; + case IPSEC_SPSTATE_PCB: + xpl->sadb_x_policy_scope = IPSEC_POLICYSCOPE_PCB; + break; + default: + xpl->sadb_x_policy_scope = IPSEC_POLICYSCOPE_GLOBAL; + } /* if is the policy for ipsec ? */ if (sp->policy == IPSEC_POLICY_IPSEC) { @@ -2388,16 +2398,25 @@ key_spdflush(struct socket *so, struct m return key_sendup_mbuf(so, m, KEY_SENDUP_ALL); } +static uint8_t +key_satype2scopemask(uint8_t satype) +{ + + if (satype == IPSEC_POLICYSCOPE_ANY) + return (0xff); + return (satype); +} /* * SADB_SPDDUMP processing * receive * - * from the user, and dump all SP leaves - * and send, + * from the user, and dump all SP leaves and send, * ..... * to the ikmpd. * - * m will always be freed. + * NOTE: + * sadb_msg_satype is considered as mask of policy scopes. + * m will always be freed. */ static int key_spddump(struct socket *so, struct mbuf *m, const struct sadb_msghdr *mhp) @@ -2406,7 +2425,7 @@ key_spddump(struct socket *so, struct mb struct secpolicy *sp; struct mbuf *n; int cnt; - u_int dir; + u_int dir, scope; IPSEC_ASSERT(so != NULL, ("null socket")); IPSEC_ASSERT(m != NULL, ("null mbuf")); @@ -2415,13 +2434,16 @@ key_spddump(struct socket *so, struct mb /* search SPD entry and get buffer size. */ cnt = 0; + scope = key_satype2scopemask(mhp->msg->sadb_msg_satype); SPTREE_RLOCK(); for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - TAILQ_FOREACH(sp, &V_sptree[dir], chain) { - cnt++; - } - TAILQ_FOREACH(sp, &V_sptree_ifnet[dir], chain) { - cnt++; + if (scope & IPSEC_POLICYSCOPE_GLOBAL) { + TAILQ_FOREACH(sp, &V_sptree[dir], chain) + cnt++; + } + if (scope & IPSEC_POLICYSCOPE_IFNET) { + TAILQ_FOREACH(sp, &V_sptree_ifnet[dir], chain) + cnt++; } } @@ -2431,21 +2453,25 @@ key_spddump(struct socket *so, struct mb } for (dir = 0; dir < IPSEC_DIR_MAX; dir++) { - TAILQ_FOREACH(sp, &V_sptree[dir], chain) { - --cnt; - n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, - mhp->msg->sadb_msg_pid); - - if (n) - key_sendup_mbuf(so, n, KEY_SENDUP_ONE); - } - TAILQ_FOREACH(sp, &V_sptree_ifnet[dir], chain) { - --cnt; - n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, - mhp->msg->sadb_msg_pid); + if (scope & IPSEC_POLICYSCOPE_GLOBAL) { + TAILQ_FOREACH(sp, &V_sptree[dir], chain) { + --cnt; + n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, + mhp->msg->sadb_msg_pid); - if (n) - key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + if (n != NULL) + key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + } + } + if (scope & IPSEC_POLICYSCOPE_IFNET) { + TAILQ_FOREACH(sp, &V_sptree_ifnet[dir], chain) { + --cnt; + n = key_setdumpsp(sp, SADB_X_SPDDUMP, cnt, + mhp->msg->sadb_msg_pid); + + if (n != NULL) + key_sendup_mbuf(so, n, KEY_SENDUP_ONE); + } } } @@ -7659,64 +7685,79 @@ key_parse(struct mbuf *m, struct socket msg = mh.msg; - /* 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: - ipseclog((LOG_DEBUG, "%s: must specify satype " - "when msg type=%u.\n", __func__, - msg->sadb_msg_type)); + /* We use satype as scope mask for spddump */ + if (msg->sadb_msg_type == SADB_X_SPDDUMP) { + switch (msg->sadb_msg_satype) { + case IPSEC_POLICYSCOPE_ANY: + case IPSEC_POLICYSCOPE_GLOBAL: + case IPSEC_POLICYSCOPE_IFNET: + case IPSEC_POLICYSCOPE_PCB: + break; + default: + ipseclog((LOG_DEBUG, "%s: illegal satype=%u\n", + __func__, msg->sadb_msg_type)); PFKEYSTAT_INC(out_invsatype); error = EINVAL; goto senderror; } - break; - case SADB_SATYPE_AH: - case SADB_SATYPE_ESP: - case SADB_X_SATYPE_IPCOMP: - case SADB_X_SATYPE_TCPSIGNATURE: - 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: - case SADB_X_SPDSETIDX: - case SADB_X_SPDUPDATE: - case SADB_X_SPDDELETE2: - ipseclog((LOG_DEBUG, "%s: illegal satype=%u\n", - __func__, msg->sadb_msg_type)); + } else { + switch (msg->sadb_msg_satype) { /* check SA type */ + 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: + ipseclog((LOG_DEBUG, "%s: must specify satype " + "when msg type=%u.\n", __func__, + msg->sadb_msg_type)); + PFKEYSTAT_INC(out_invsatype); + error = EINVAL; + goto senderror; + } + break; + case SADB_SATYPE_AH: + case SADB_SATYPE_ESP: + case SADB_X_SATYPE_IPCOMP: + case SADB_X_SATYPE_TCPSIGNATURE: + switch (msg->sadb_msg_type) { + case SADB_X_SPDADD: + case SADB_X_SPDDELETE: + case SADB_X_SPDGET: + case SADB_X_SPDFLUSH: + case SADB_X_SPDSETIDX: + case SADB_X_SPDUPDATE: + case SADB_X_SPDDELETE2: + ipseclog((LOG_DEBUG, "%s: illegal satype=%u\n", + __func__, msg->sadb_msg_type)); + PFKEYSTAT_INC(out_invsatype); + error = EINVAL; + goto senderror; + } + break; + case SADB_SATYPE_RSVP: + case SADB_SATYPE_OSPFV2: + case SADB_SATYPE_RIPV2: + case SADB_SATYPE_MIP: + ipseclog((LOG_DEBUG, "%s: type %u isn't supported.\n", + __func__, msg->sadb_msg_satype)); + PFKEYSTAT_INC(out_invsatype); + error = EOPNOTSUPP; + goto senderror; + case 1: /* XXX: What does it do? */ + if (msg->sadb_msg_type == SADB_X_PROMISC) + break; + /*FALLTHROUGH*/ + default: + ipseclog((LOG_DEBUG, "%s: invalid type %u is passed.\n", + __func__, msg->sadb_msg_satype)); PFKEYSTAT_INC(out_invsatype); error = EINVAL; goto senderror; } - break; - case SADB_SATYPE_RSVP: - case SADB_SATYPE_OSPFV2: - case SADB_SATYPE_RIPV2: - case SADB_SATYPE_MIP: - ipseclog((LOG_DEBUG, "%s: type %u isn't supported.\n", - __func__, msg->sadb_msg_satype)); - PFKEYSTAT_INC(out_invsatype); - error = EOPNOTSUPP; - goto senderror; - case 1: /* XXX: What does it do? */ - if (msg->sadb_msg_type == SADB_X_PROMISC) - break; - /*FALLTHROUGH*/ - default: - ipseclog((LOG_DEBUG, "%s: invalid type %u is passed.\n", - __func__, msg->sadb_msg_satype)); - PFKEYSTAT_INC(out_invsatype); - error = EINVAL; - goto senderror; } /* check field of upper layer protocol and address family */