source: rtems-libbsd/ipsec-tools/src/libipsec/pfkey.c @ e474ada

Last change on this file since e474ada was e474ada, checked in by Christian Mauderer <christian.mauderer@…>, on 05/10/21 at 06:50:52

ipsec-tools/pfkey: Fix socket leak

setkey uses pfkey_open to open a socket. But setkey doesn't close the
socket.

The libipsec functions are used only by user space applications (setkey
and racoon). Adding the wrapper for socket makes sure that the opened
socket is registered and closes if the application exits.

Fixes #4405

  • Property mode set to 100644
File size: 60.0 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3#ifdef __rtems__
4/* Only need socket from rtems-bsd-program wrappers! */
5int
6rtems_bsd_program_socket(int domain, int type, int protocol);
7#define socket(domain, type, protocol) \
8    rtems_bsd_program_socket(domain, type, protocol)
9#endif /* __rtems__ */
10/*      $NetBSD: pfkey.c,v 1.21.2.1 2011/11/14 13:25:06 tteras Exp $    */
11
12/*      $KAME: pfkey.c,v 1.47 2003/10/02 19:52:12 itojun Exp $  */
13
14/*
15 * Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions
20 * are met:
21 * 1. Redistributions of source code must retain the above copyright
22 *    notice, this list of conditions and the following disclaimer.
23 * 2. Redistributions in binary form must reproduce the above copyright
24 *    notice, this list of conditions and the following disclaimer in the
25 *    documentation and/or other materials provided with the distribution.
26 * 3. Neither the name of the project nor the names of its contributors
27 *    may be used to endorse or promote products derived from this software
28 *    without specific prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 */
42
43#ifdef HAVE_CONFIG_H
44#include "config.h"
45#endif
46
47#include <sys/types.h>
48#include <sys/param.h>
49#include <sys/socket.h>
50#include <net/pfkeyv2.h>
51#include <netinet/in.h>
52#include PATH_IPSEC_H
53
54#include <stdlib.h>
55#include <unistd.h>
56#include <string.h>
57#include <errno.h>
58#include <stdio.h>
59
60#include "ipsec_strerror.h"
61#include "libpfkey.h"
62
63#define CALLOC(size, cast) (cast)calloc(1, (size))
64
65static int findsupportedmap __P((int));
66static int setsupportedmap __P((struct sadb_supported *));
67static struct sadb_alg *findsupportedalg __P((u_int, u_int));
68static int pfkey_send_x1 __P((struct pfkey_send_sa_args *));
69static int pfkey_send_x2 __P((int, u_int, u_int, u_int,
70        struct sockaddr *, struct sockaddr *, u_int32_t));
71static int pfkey_send_x3 __P((int, u_int, u_int));
72static int pfkey_send_x4 __P((int, u_int, struct sockaddr *, u_int,
73        struct sockaddr *, u_int, u_int, u_int64_t, u_int64_t,
74        char *, int, u_int32_t));
75static int pfkey_send_x5 __P((int, u_int, u_int32_t));
76
77static caddr_t pfkey_setsadbmsg __P((caddr_t, caddr_t, u_int, u_int,
78        u_int, u_int32_t, pid_t));
79static caddr_t pfkey_setsadbsa __P((caddr_t, caddr_t, u_int32_t, u_int,
80        u_int, u_int, u_int32_t));
81static caddr_t pfkey_setsadbaddr __P((caddr_t, caddr_t, u_int,
82        struct sockaddr *, u_int, u_int));
83
84#ifdef SADB_X_EXT_KMADDRESS
85static caddr_t pfkey_setsadbkmaddr __P((caddr_t, caddr_t, struct sockaddr *,
86        struct sockaddr *));
87#endif
88
89static caddr_t pfkey_setsadbkey __P((caddr_t, caddr_t, u_int, caddr_t, u_int));
90static caddr_t pfkey_setsadblifetime __P((caddr_t, caddr_t, u_int, u_int32_t,
91        u_int32_t, u_int32_t, u_int32_t));
92static caddr_t pfkey_setsadbxsa2 __P((caddr_t, caddr_t, u_int32_t, u_int32_t));
93
94#ifdef SADB_X_EXT_NAT_T_TYPE
95static caddr_t pfkey_set_natt_type __P((caddr_t, caddr_t, u_int, u_int8_t));
96static caddr_t pfkey_set_natt_port __P((caddr_t, caddr_t, u_int, u_int16_t));
97#endif
98#ifdef SADB_X_EXT_NAT_T_FRAG
99static caddr_t pfkey_set_natt_frag __P((caddr_t, caddr_t, u_int, u_int16_t));
100#endif
101
102#ifdef SADB_X_EXT_SEC_CTX
103static caddr_t pfkey_setsecctx __P((caddr_t, caddr_t, u_int, u_int8_t, u_int8_t,
104                                    caddr_t, u_int16_t));
105#endif
106
107#ifndef __rtems__
108int libipsec_opt = 0
109#else /* __rtems__ */
110const int libipsec_opt = 0
111#endif /* __rtems__ */
112#ifdef SADB_X_EXT_NAT_T_TYPE
113        | LIBIPSEC_OPT_NATT
114#endif
115#ifdef SADB_X_EXT_NAT_T_FRAG
116        | LIBIPSEC_OPT_FRAG
117#endif
118#ifdef SADB_X_EXT_NAT_T_SEC_CTX
119        | LIBIPSEC_OPT_SEC_CTX
120#endif
121        ;
122
123/*
124 * make and search supported algorithm structure.
125 */
126static struct sadb_supported *ipsec_supported[] = { NULL, NULL, NULL,
127#ifdef SADB_X_SATYPE_TCPSIGNATURE
128    NULL,
129#endif
130};
131
132#ifndef __rtems__
133static int supported_map[] = {
134#else /* __rtems__ */
135static const int supported_map[] = {
136#endif /* __rtems__ */
137        SADB_SATYPE_AH,
138        SADB_SATYPE_ESP,
139        SADB_X_SATYPE_IPCOMP,
140#ifdef SADB_X_SATYPE_TCPSIGNATURE
141        SADB_X_SATYPE_TCPSIGNATURE,
142#endif
143};
144
145static int
146findsupportedmap(satype)
147        int satype;
148{
149        int i;
150
151        for (i = 0; i < sizeof(supported_map)/sizeof(supported_map[0]); i++)
152                if (supported_map[i] == satype)
153                        return i;
154        return -1;
155}
156
157static struct sadb_alg *
158findsupportedalg(satype, alg_id)
159        u_int satype, alg_id;
160{
161        int algno;
162        int tlen;
163        caddr_t p;
164
165        /* validity check */
166        algno = findsupportedmap((int)satype);
167        if (algno == -1) {
168                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
169                return NULL;
170        }
171        if (ipsec_supported[algno] == NULL) {
172                __ipsec_errcode = EIPSEC_DO_GET_SUPP_LIST;
173                return NULL;
174        }
175
176        tlen = ipsec_supported[algno]->sadb_supported_len
177                - sizeof(struct sadb_supported);
178        p = (void *)(ipsec_supported[algno] + 1);
179        while (tlen > 0) {
180                if (tlen < sizeof(struct sadb_alg)) {
181                        /* invalid format */
182                        break;
183                }
184                if (((struct sadb_alg *)(void *)p)->sadb_alg_id == alg_id)
185                        return (void *)p;
186
187                tlen -= sizeof(struct sadb_alg);
188                p += sizeof(struct sadb_alg);
189        }
190
191        __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
192        return NULL;
193}
194
195static int
196setsupportedmap(sup)
197        struct sadb_supported *sup;
198{
199        struct sadb_supported **ipsup;
200
201        switch (sup->sadb_supported_exttype) {
202        case SADB_EXT_SUPPORTED_AUTH:
203                ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_AH)];
204                break;
205        case SADB_EXT_SUPPORTED_ENCRYPT:
206                ipsup = &ipsec_supported[findsupportedmap(SADB_SATYPE_ESP)];
207                break;
208        default:
209                __ipsec_errcode = EIPSEC_INVAL_SATYPE;
210                return -1;
211        }
212
213        if (*ipsup)
214                free(*ipsup);
215
216        *ipsup = malloc((size_t)sup->sadb_supported_len);
217        if (!*ipsup) {
218                __ipsec_set_strerror(strerror(errno));
219                return -1;
220        }
221        memcpy(*ipsup, sup, (size_t)sup->sadb_supported_len);
222
223        return 0;
224}
225
226/*
227 * check key length against algorithm specified.
228 * This function is called with SADB_EXT_SUPPORTED_{AUTH,ENCRYPT} as the
229 * augument, and only calls to ipsec_check_keylen2();
230 * keylen is the unit of bit.
231 * OUT:
232 *      -1: invalid.
233 *       0: valid.
234 */
235int
236ipsec_check_keylen(supported, alg_id, keylen)
237        u_int supported;
238        u_int alg_id;
239        u_int keylen;
240{
241        u_int satype;
242
243        /* validity check */
244        switch (supported) {
245        case SADB_EXT_SUPPORTED_AUTH:
246                satype = SADB_SATYPE_AH;
247                break;
248        case SADB_EXT_SUPPORTED_ENCRYPT:
249                satype = SADB_SATYPE_ESP;
250                break;
251        default:
252                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
253                return -1;
254        }
255
256        return ipsec_check_keylen2(satype, alg_id, keylen);
257}
258
259/*
260 * check key length against algorithm specified.
261 * satype is one of satype defined at pfkeyv2.h.
262 * keylen is the unit of bit.
263 * OUT:
264 *      -1: invalid.
265 *       0: valid.
266 */
267int
268ipsec_check_keylen2(satype, alg_id, keylen)
269        u_int satype;
270        u_int alg_id;
271        u_int keylen;
272{
273        struct sadb_alg *alg;
274
275        alg = findsupportedalg(satype, alg_id);
276        if (!alg)
277                return -1;
278
279        if (keylen < alg->sadb_alg_minbits || keylen > alg->sadb_alg_maxbits) {
280                fprintf(stderr, "%d %d %d\n", keylen, alg->sadb_alg_minbits,
281                        alg->sadb_alg_maxbits);
282                __ipsec_errcode = EIPSEC_INVAL_KEYLEN;
283                return -1;
284        }
285
286        __ipsec_errcode = EIPSEC_NO_ERROR;
287        return 0;
288}
289
290/*
291 * get max/min key length against algorithm specified.
292 * satype is one of satype defined at pfkeyv2.h.
293 * keylen is the unit of bit.
294 * OUT:
295 *      -1: invalid.
296 *       0: valid.
297 */
298int
299ipsec_get_keylen(supported, alg_id, alg0)
300        u_int supported, alg_id;
301        struct sadb_alg *alg0;
302{
303        struct sadb_alg *alg;
304        u_int satype;
305
306        /* validity check */
307        if (!alg0) {
308                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
309                return -1;
310        }
311
312        switch (supported) {
313        case SADB_EXT_SUPPORTED_AUTH:
314                satype = SADB_SATYPE_AH;
315                break;
316        case SADB_EXT_SUPPORTED_ENCRYPT:
317                satype = SADB_SATYPE_ESP;
318                break;
319        default:
320                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
321                return -1;
322        }
323
324        alg = findsupportedalg(satype, alg_id);
325        if (!alg)
326                return -1;
327
328        memcpy(alg0, alg, sizeof(*alg0));
329
330        __ipsec_errcode = EIPSEC_NO_ERROR;
331        return 0;
332}
333
334/*
335 * set the rate for SOFT lifetime against HARD one.
336 * If rate is more than 100 or equal to zero, then set to 100.
337 */
338static u_int soft_lifetime_allocations_rate = PFKEY_SOFT_LIFETIME_RATE;
339static u_int soft_lifetime_bytes_rate = PFKEY_SOFT_LIFETIME_RATE;
340static u_int soft_lifetime_addtime_rate = PFKEY_SOFT_LIFETIME_RATE;
341static u_int soft_lifetime_usetime_rate = PFKEY_SOFT_LIFETIME_RATE;
342
343u_int
344pfkey_set_softrate(type, rate)
345        u_int type, rate;
346{
347        __ipsec_errcode = EIPSEC_NO_ERROR;
348
349        if (rate > 100 || rate == 0)
350                rate = 100;
351
352        switch (type) {
353        case SADB_X_LIFETIME_ALLOCATIONS:
354                soft_lifetime_allocations_rate = rate;
355                return 0;
356        case SADB_X_LIFETIME_BYTES:
357                soft_lifetime_bytes_rate = rate;
358                return 0;
359        case SADB_X_LIFETIME_ADDTIME:
360                soft_lifetime_addtime_rate = rate;
361                return 0;
362        case SADB_X_LIFETIME_USETIME:
363                soft_lifetime_usetime_rate = rate;
364                return 0;
365        }
366
367        __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
368        return 1;
369}
370
371/*
372 * get current rate for SOFT lifetime against HARD one.
373 * ATTENTION: ~0 is returned if invalid type was passed.
374 */
375u_int
376pfkey_get_softrate(type)
377        u_int type;
378{
379        switch (type) {
380        case SADB_X_LIFETIME_ALLOCATIONS:
381                return soft_lifetime_allocations_rate;
382        case SADB_X_LIFETIME_BYTES:
383                return soft_lifetime_bytes_rate;
384        case SADB_X_LIFETIME_ADDTIME:
385                return soft_lifetime_addtime_rate;
386        case SADB_X_LIFETIME_USETIME:
387                return soft_lifetime_usetime_rate;
388        }
389
390        return (u_int)~0;
391}
392
393/*
394 * sending SADB_GETSPI message to the kernel.
395 * OUT:
396 *      positive: success and return length sent.
397 *      -1      : error occured, and set errno.
398 */
399int
400pfkey_send_getspi_nat(int so, u_int satype, u_int mode, struct sockaddr *src,
401    struct sockaddr *dst, u_int8_t natt_type, u_int16_t sport,
402    u_int16_t dport, u_int32_t min, u_int32_t max, u_int32_t reqid,
403    u_int32_t seq)
404{
405        struct sadb_msg *newmsg;
406        caddr_t ep;
407        int len;
408        int need_spirange = 0;
409        caddr_t p;
410        int plen;
411
412        /* validity check */
413        if (src == NULL || dst == NULL) {
414                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
415                return -1;
416        }
417        if (src->sa_family != dst->sa_family) {
418                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
419                return -1;
420        }
421        if (min > max || (min > 0 && min <= 255)) {
422                __ipsec_errcode = EIPSEC_INVAL_SPI;
423                return -1;
424        }
425        switch (src->sa_family) {
426        case AF_INET:
427                plen = sizeof(struct in_addr) << 3;
428                break;
429        case AF_INET6:
430                plen = sizeof(struct in6_addr) << 3;
431                break;
432        default:
433                __ipsec_errcode = EIPSEC_INVAL_FAMILY;
434                return -1;
435        }
436
437        /* create new sadb_msg to send. */
438        len = sizeof(struct sadb_msg)
439                + sizeof(struct sadb_x_sa2)
440                + sizeof(struct sadb_address)
441                + PFKEY_ALIGN8(sysdep_sa_len(src))
442                + sizeof(struct sadb_address)
443                + PFKEY_ALIGN8(sysdep_sa_len(dst));
444
445        if (min > 255 && max < (u_int)~0) {
446                need_spirange++;
447                len += sizeof(struct sadb_spirange);
448        }
449
450#ifdef SADB_X_EXT_NAT_T_TYPE
451        if(natt_type||sport||dport){
452                len += sizeof(struct sadb_x_nat_t_type);
453                len += sizeof(struct sadb_x_nat_t_port);
454                len += sizeof(struct sadb_x_nat_t_port);
455        }
456#endif
457
458        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
459                __ipsec_set_strerror(strerror(errno));
460                return -1;
461        }
462        ep = ((caddr_t)(void *)newmsg) + len;
463
464        p = pfkey_setsadbmsg((void *)newmsg, ep, SADB_GETSPI,
465            (u_int)len, satype, seq, getpid());
466        if (!p) {
467                free(newmsg);
468                return -1;
469        }
470
471        p = pfkey_setsadbxsa2(p, ep, mode, reqid);
472        if (!p) {
473                free(newmsg);
474                return -1;
475        }
476
477        /* set sadb_address for source */
478        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
479            IPSEC_ULPROTO_ANY);
480        if (!p) {
481                free(newmsg);
482                return -1;
483        }
484
485        /* set sadb_address for destination */
486        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
487            IPSEC_ULPROTO_ANY);
488        if (!p) {
489                free(newmsg);
490                return -1;
491        }
492
493#ifdef SADB_X_EXT_NAT_T_TYPE
494        /* Add nat-t messages */
495        if (natt_type) {
496                p = pfkey_set_natt_type(p, ep, SADB_X_EXT_NAT_T_TYPE,
497                                        natt_type);
498                if (!p) {
499                        free(newmsg);
500                        return -1;
501                }
502
503                p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_SPORT,
504                                        sport);
505                if (!p) {
506                        free(newmsg);
507                        return -1;
508                }
509
510                p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_DPORT,
511                                        dport);
512                if (!p) {
513                        free(newmsg);
514                        return -1;
515                }
516        }
517#endif
518
519        /* proccessing spi range */
520        if (need_spirange) {
521                struct sadb_spirange spirange;
522
523                if (p + sizeof(spirange) > ep) {
524                        free(newmsg);
525                        return -1;
526                }
527
528                memset(&spirange, 0, sizeof(spirange));
529                spirange.sadb_spirange_len = PFKEY_UNIT64(sizeof(spirange));
530                spirange.sadb_spirange_exttype = SADB_EXT_SPIRANGE;
531                spirange.sadb_spirange_min = min;
532                spirange.sadb_spirange_max = max;
533
534                memcpy(p, &spirange, sizeof(spirange));
535
536                p += sizeof(spirange);
537        }
538        if (p != ep) {
539                free(newmsg);
540                return -1;
541        }
542
543        /* send message */
544        len = pfkey_send(so, newmsg, len);
545        free(newmsg);
546
547        if (len < 0)
548                return -1;
549
550        __ipsec_errcode = EIPSEC_NO_ERROR;
551        return len;
552}
553
554int
555pfkey_send_getspi(int so, u_int satype, u_int mode, struct sockaddr *src,
556    struct sockaddr *dst, u_int32_t min, u_int32_t max, u_int32_t reqid,
557    u_int32_t seq)
558{
559        return pfkey_send_getspi_nat(so, satype, mode, src, dst, 0, 0, 0,
560                min, max, reqid, seq);
561}
562
563/*
564 * sending SADB_UPDATE message to the kernel.
565 * The length of key material is a_keylen + e_keylen.
566 * OUT:
567 *      positive: success and return length sent.
568 *      -1      : error occured, and set errno.
569 */
570int
571pfkey_send_update2(struct pfkey_send_sa_args *sa_parms)
572{
573        int len;
574
575        sa_parms->type = SADB_UPDATE;
576        if ((len = pfkey_send_x1(sa_parms)) < 0)
577                return -1;
578
579        return len;
580}
581
582/*
583 * sending SADB_ADD message to the kernel.
584 * The length of key material is a_keylen + e_keylen.
585 * OUT:
586 *      positive: success and return length sent.
587 *      -1      : error occured, and set errno.
588 */
589int
590pfkey_send_add2(struct pfkey_send_sa_args *sa_parms)
591{
592        int len;
593       
594        sa_parms->type = SADB_ADD;
595        if ((len = pfkey_send_x1(sa_parms)) < 0)
596                return -1;
597
598        return len;
599}
600
601/*
602 * sending SADB_DELETE message to the kernel.
603 * OUT:
604 *      positive: success and return length sent.
605 *      -1      : error occured, and set errno.
606 */
607int
608pfkey_send_delete(int so, u_int satype, u_int mode, struct sockaddr *src,
609    struct sockaddr *dst, u_int32_t spi)
610{
611        int len;
612        if ((len = pfkey_send_x2(so, SADB_DELETE, satype, mode, src, dst, spi)) < 0)
613                return -1;
614
615        return len;
616}
617
618/*
619 * sending SADB_DELETE without spi to the kernel.  This is
620 * the "delete all" request (an extension also present in
621 * Solaris).
622 *
623 * OUT:
624 *      positive: success and return length sent
625 *      -1      : error occured, and set errno
626 */
627/*ARGSUSED*/
628int
629pfkey_send_delete_all(int so, u_int satype, u_int mode, struct sockaddr *src,
630    struct sockaddr *dst)
631{
632        struct sadb_msg *newmsg;
633        int len;
634        caddr_t p;
635        int plen;
636        caddr_t ep;
637
638        /* validity check */
639        if (src == NULL || dst == NULL) {
640                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
641                return -1;
642        }
643        if (src->sa_family != dst->sa_family) {
644                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
645                return -1;
646        }
647        switch (src->sa_family) {
648        case AF_INET:
649                plen = sizeof(struct in_addr) << 3;
650                break;
651        case AF_INET6:
652                plen = sizeof(struct in6_addr) << 3;
653                break;
654        default:
655                __ipsec_errcode = EIPSEC_INVAL_FAMILY;
656                return -1;
657        }
658
659        /* create new sadb_msg to reply. */
660        len = sizeof(struct sadb_msg)
661                + sizeof(struct sadb_address)
662                + PFKEY_ALIGN8(sysdep_sa_len(src))
663                + sizeof(struct sadb_address)
664                + PFKEY_ALIGN8(sysdep_sa_len(dst));
665
666        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
667                __ipsec_set_strerror(strerror(errno));
668                return -1;
669        }
670        ep = ((caddr_t)(void *)newmsg) + len;
671
672        p = pfkey_setsadbmsg((void *)newmsg, ep, SADB_DELETE, (u_int)len,
673            satype, 0, getpid());
674        if (!p) {
675                free(newmsg);
676                return -1;
677        }
678        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
679            IPSEC_ULPROTO_ANY);
680        if (!p) {
681                free(newmsg);
682                return -1;
683        }
684        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
685            IPSEC_ULPROTO_ANY);
686        if (!p || p != ep) {
687                free(newmsg);
688                return -1;
689        }
690
691        /* send message */
692        len = pfkey_send(so, newmsg, len);
693        free(newmsg);
694
695        if (len < 0)
696                return -1;
697
698        __ipsec_errcode = EIPSEC_NO_ERROR;
699        return len;
700}
701
702/*
703 * sending SADB_GET message to the kernel.
704 * OUT:
705 *      positive: success and return length sent.
706 *      -1      : error occured, and set errno.
707 */
708int
709pfkey_send_get(int so, u_int satype, u_int mode, struct sockaddr *src,
710    struct sockaddr *dst, u_int32_t spi)
711{
712        int len;
713        if ((len = pfkey_send_x2(so, SADB_GET, satype, mode, src, dst, spi)) < 0)
714                return -1;
715
716        return len;
717}
718
719/*
720 * sending SADB_REGISTER message to the kernel.
721 * OUT:
722 *      positive: success and return length sent.
723 *      -1      : error occured, and set errno.
724 */
725int
726pfkey_send_register(int so, u_int satype)
727{
728        int len, algno;
729
730        if (satype == PF_UNSPEC) {
731                for (algno = 0;
732                     algno < sizeof(supported_map)/sizeof(supported_map[0]);
733                     algno++) {
734                        if (ipsec_supported[algno]) {
735                                free(ipsec_supported[algno]);
736                                ipsec_supported[algno] = NULL;
737                        }
738                }
739        } else {
740                algno = findsupportedmap((int)satype);
741                if (algno == -1) {
742                        __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
743                        return -1;
744                }
745
746                if (ipsec_supported[algno]) {
747                        free(ipsec_supported[algno]);
748                        ipsec_supported[algno] = NULL;
749                }
750        }
751
752        if ((len = pfkey_send_x3(so, SADB_REGISTER, satype)) < 0)
753                return -1;
754
755        return len;
756}
757
758/*
759 * receiving SADB_REGISTER message from the kernel, and copy buffer for
760 * sadb_supported returned into ipsec_supported.
761 * OUT:
762 *       0: success and return length sent.
763 *      -1: error occured, and set errno.
764 */
765int
766pfkey_recv_register(int so)
767{
768        pid_t pid = getpid();
769        struct sadb_msg *newmsg;
770        int error = -1;
771
772        /* receive message */
773        for (;;) {
774                if ((newmsg = pfkey_recv(so)) == NULL)
775                        return -1;
776                if (newmsg->sadb_msg_type == SADB_REGISTER &&
777                    newmsg->sadb_msg_pid == pid)
778                        break;
779                free(newmsg);
780        }
781
782        /* check and fix */
783        newmsg->sadb_msg_len = PFKEY_UNUNIT64(newmsg->sadb_msg_len);
784
785        error = pfkey_set_supported(newmsg, newmsg->sadb_msg_len);
786        free(newmsg);
787
788        if (error == 0)
789                __ipsec_errcode = EIPSEC_NO_ERROR;
790
791        return error;
792}
793
794/*
795 * receiving SADB_REGISTER message from the kernel, and copy buffer for
796 * sadb_supported returned into ipsec_supported.
797 * NOTE: sadb_msg_len must be host order.
798 * IN:
799 *      tlen: msg length, it's to makeing sure.
800 * OUT:
801 *       0: success and return length sent.
802 *      -1: error occured, and set errno.
803 */
804int
805pfkey_set_supported(struct sadb_msg *msg, int tlen)
806{
807        struct sadb_supported *sup;
808        caddr_t p;
809        caddr_t ep;
810
811        /* validity */
812        if (msg->sadb_msg_len != tlen) {
813                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
814                return -1;
815        }
816
817        p = (void *)msg;
818        ep = p + tlen;
819
820        p += sizeof(struct sadb_msg);
821
822        while (p < ep) {
823                sup = (void *)p;
824                if (ep < p + sizeof(*sup) ||
825                    PFKEY_EXTLEN(sup) < sizeof(*sup) ||
826                    ep < p + sup->sadb_supported_len) {
827                        /* invalid format */
828                        break;
829                }
830
831                switch (sup->sadb_supported_exttype) {
832                case SADB_EXT_SUPPORTED_AUTH:
833                case SADB_EXT_SUPPORTED_ENCRYPT:
834                        break;
835                default:
836                        __ipsec_errcode = EIPSEC_INVAL_SATYPE;
837                        return -1;
838                }
839
840                /* fixed length */
841                sup->sadb_supported_len = PFKEY_EXTLEN(sup);
842
843                /* set supported map */
844                if (setsupportedmap(sup) != 0)
845                        return -1;
846
847                p += sup->sadb_supported_len;
848        }
849
850        if (p != ep) {
851                __ipsec_errcode = EIPSEC_INVAL_SATYPE;
852                return -1;
853        }
854
855        __ipsec_errcode = EIPSEC_NO_ERROR;
856
857        return 0;
858}
859
860/*
861 * sending SADB_FLUSH message to the kernel.
862 * OUT:
863 *      positive: success and return length sent.
864 *      -1      : error occured, and set errno.
865 */
866int
867pfkey_send_flush(int so, u_int satype)
868{
869        int len;
870
871        if ((len = pfkey_send_x3(so, SADB_FLUSH, satype)) < 0)
872                return -1;
873
874        return len;
875}
876
877/*
878 * sending SADB_DUMP message to the kernel.
879 * OUT:
880 *      positive: success and return length sent.
881 *      -1      : error occured, and set errno.
882 */
883int
884pfkey_send_dump(int so, u_int satype)
885{
886        int len;
887
888        if ((len = pfkey_send_x3(so, SADB_DUMP, satype)) < 0)
889                return -1;
890
891        return len;
892}
893
894/*
895 * sending SADB_X_PROMISC message to the kernel.
896 * NOTE that this function handles promisc mode toggle only.
897 * IN:
898 *      flag:   set promisc off if zero, set promisc on if non-zero.
899 * OUT:
900 *      positive: success and return length sent.
901 *      -1      : error occured, and set errno.
902 *      0     : error occured, and set errno.
903 *      others: a pointer to new allocated buffer in which supported
904 *              algorithms is.
905 */
906int
907pfkey_send_promisc_toggle(int so, int flag)
908{
909        int len;
910
911        if ((len = pfkey_send_x3(so, SADB_X_PROMISC,
912            (u_int)(flag ? 1 : 0))) < 0)
913                return -1;
914
915        return len;
916}
917
918/*
919 * sending SADB_X_SPDADD message to the kernel.
920 * OUT:
921 *      positive: success and return length sent.
922 *      -1      : error occured, and set errno.
923 */
924int
925pfkey_send_spdadd(int so, struct sockaddr *src, u_int prefs,
926    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
927    int policylen, u_int32_t seq)
928{
929        int len;
930
931        if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
932                                src, prefs, dst, prefd, proto,
933                                (u_int64_t)0, (u_int64_t)0,
934                                policy, policylen, seq)) < 0)
935                return -1;
936
937        return len;
938}
939
940/*
941 * sending SADB_X_SPDADD message to the kernel.
942 * OUT:
943 *      positive: success and return length sent.
944 *      -1      : error occured, and set errno.
945 */
946int
947pfkey_send_spdadd2(int so, struct sockaddr *src, u_int prefs,
948    struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime,
949    u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq)
950{
951        int len;
952
953        if ((len = pfkey_send_x4(so, SADB_X_SPDADD,
954                                src, prefs, dst, prefd, proto,
955                                ltime, vtime,
956                                policy, policylen, seq)) < 0)
957                return -1;
958
959        return len;
960}
961
962/*
963 * sending SADB_X_SPDUPDATE message to the kernel.
964 * OUT:
965 *      positive: success and return length sent.
966 *      -1      : error occured, and set errno.
967 */
968int
969pfkey_send_spdupdate(int so, struct sockaddr *src, u_int prefs,
970    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
971    int policylen, u_int32_t seq)
972{
973        int len;
974
975        if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
976                                src, prefs, dst, prefd, proto,
977                                (u_int64_t)0, (u_int64_t)0,
978                                policy, policylen, seq)) < 0)
979                return -1;
980
981        return len;
982}
983
984/*
985 * sending SADB_X_SPDUPDATE message to the kernel.
986 * OUT:
987 *      positive: success and return length sent.
988 *      -1      : error occured, and set errno.
989 */
990int
991pfkey_send_spdupdate2(int so, struct sockaddr *src, u_int prefs,
992    struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime,
993    u_int64_t vtime, caddr_t policy, int policylen, u_int32_t seq)
994{
995        int len;
996
997        if ((len = pfkey_send_x4(so, SADB_X_SPDUPDATE,
998                                src, prefs, dst, prefd, proto,
999                                ltime, vtime,
1000                                policy, policylen, seq)) < 0)
1001                return -1;
1002
1003        return len;
1004}
1005
1006/*
1007 * sending SADB_X_SPDDELETE message to the kernel.
1008 * OUT:
1009 *      positive: success and return length sent.
1010 *      -1      : error occured, and set errno.
1011 */
1012int
1013pfkey_send_spddelete(int so, struct sockaddr *src, u_int prefs,
1014    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
1015    int policylen, u_int32_t seq)
1016{
1017        int len;
1018
1019        if (policylen != sizeof(struct sadb_x_policy)) {
1020                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1021                return -1;
1022        }
1023
1024        if ((len = pfkey_send_x4(so, SADB_X_SPDDELETE,
1025                                src, prefs, dst, prefd, proto,
1026                                (u_int64_t)0, (u_int64_t)0,
1027                                policy, policylen, seq)) < 0)
1028                return -1;
1029
1030        return len;
1031}
1032
1033/*
1034 * sending SADB_X_SPDDELETE message to the kernel.
1035 * OUT:
1036 *      positive: success and return length sent.
1037 *      -1      : error occured, and set errno.
1038 */
1039int
1040pfkey_send_spddelete2(int so, u_int32_t spid)
1041{
1042        int len;
1043
1044        if ((len = pfkey_send_x5(so, SADB_X_SPDDELETE2, spid)) < 0)
1045                return -1;
1046
1047        return len;
1048}
1049
1050/*
1051 * sending SADB_X_SPDGET message to the kernel.
1052 * OUT:
1053 *      positive: success and return length sent.
1054 *      -1      : error occured, and set errno.
1055 */
1056int
1057pfkey_send_spdget(int so, u_int32_t spid)
1058{
1059        int len;
1060
1061        if ((len = pfkey_send_x5(so, SADB_X_SPDGET, spid)) < 0)
1062                return -1;
1063
1064        return len;
1065}
1066
1067/*
1068 * sending SADB_X_SPDSETIDX message to the kernel.
1069 * OUT:
1070 *      positive: success and return length sent.
1071 *      -1      : error occured, and set errno.
1072 */
1073int
1074pfkey_send_spdsetidx(int so, struct sockaddr *src, u_int prefs,
1075    struct sockaddr *dst, u_int prefd, u_int proto, caddr_t policy,
1076    int policylen, u_int32_t seq)
1077{
1078        int len;
1079
1080        if (policylen != sizeof(struct sadb_x_policy)) {
1081                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1082                return -1;
1083        }
1084
1085        if ((len = pfkey_send_x4(so, SADB_X_SPDSETIDX,
1086                                src, prefs, dst, prefd, proto,
1087                                (u_int64_t)0, (u_int64_t)0,
1088                                policy, policylen, seq)) < 0)
1089                return -1;
1090
1091        return len;
1092}
1093
1094/*
1095 * sending SADB_SPDFLUSH message to the kernel.
1096 * OUT:
1097 *      positive: success and return length sent.
1098 *      -1      : error occured, and set errno.
1099 */
1100int
1101pfkey_send_spdflush(int so)
1102{
1103        int len;
1104
1105        if ((len = pfkey_send_x3(so, SADB_X_SPDFLUSH, SADB_SATYPE_UNSPEC)) < 0)
1106                return -1;
1107
1108        return len;
1109}
1110
1111/*
1112 * sending SADB_SPDDUMP message to the kernel.
1113 * OUT:
1114 *      positive: success and return length sent.
1115 *      -1      : error occured, and set errno.
1116 */
1117int
1118pfkey_send_spddump(int so)
1119{
1120        int len;
1121
1122        if ((len = pfkey_send_x3(so, SADB_X_SPDDUMP, SADB_SATYPE_UNSPEC)) < 0)
1123                return -1;
1124
1125        return len;
1126}
1127
1128
1129#ifdef SADB_X_MIGRATE
1130/*
1131 * sending SADB_X_MIGRATE message to the kernel.
1132 * OUT:
1133 *      positive: success and return length sent.
1134 *      -1      : error occured, and set errno.
1135 */
1136int
1137pfkey_send_migrate(int so, struct sockaddr *local, struct sockaddr *remote,
1138    struct sockaddr *src, u_int prefs, struct sockaddr *dst, u_int prefd,
1139    u_int proto, caddr_t policy, int policylen, u_int32_t seq)
1140{
1141        struct sadb_msg *newmsg;
1142        int len;
1143        caddr_t p;
1144        int plen;
1145        caddr_t ep;
1146
1147        /* validity check */
1148        if (src == NULL || dst == NULL) {
1149                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1150                return -1;
1151        }
1152        if (src->sa_family != dst->sa_family) {
1153                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
1154                return -1;
1155        }
1156
1157        if (local == NULL || remote == NULL) {
1158                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1159                return -1;
1160        }
1161#ifdef SADB_X_EXT_KMADDRESS
1162        if (local->sa_family != remote->sa_family) {
1163                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
1164                return -1;
1165        }
1166#endif
1167
1168        switch (src->sa_family) {
1169        case AF_INET:
1170                plen = sizeof(struct in_addr) << 3;
1171                break;
1172        case AF_INET6:
1173                plen = sizeof(struct in6_addr) << 3;
1174                break;
1175        default:
1176                __ipsec_errcode = EIPSEC_INVAL_FAMILY;
1177                return -1;
1178        }
1179        if (prefs > plen || prefd > plen) {
1180                __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
1181                return -1;
1182        }
1183
1184        /* create new sadb_msg to reply. */
1185        len = sizeof(struct sadb_msg)
1186#ifdef SADB_X_EXT_KMADDRESS
1187                + sizeof(struct sadb_x_kmaddress)
1188                + PFKEY_ALIGN8(2*sysdep_sa_len(local))
1189#endif
1190                + sizeof(struct sadb_address)
1191                + PFKEY_ALIGN8(sysdep_sa_len(src))
1192                + sizeof(struct sadb_address)
1193                + PFKEY_ALIGN8(sysdep_sa_len(dst))
1194                + policylen;
1195
1196        if ((newmsg = CALLOC(len, struct sadb_msg *)) == NULL) {
1197                __ipsec_set_strerror(strerror(errno));
1198                return -1;
1199        }
1200        ep = ((caddr_t)newmsg) + len;
1201
1202        p = pfkey_setsadbmsg((caddr_t)newmsg, ep, SADB_X_MIGRATE, (u_int)len,
1203            SADB_SATYPE_UNSPEC, seq, getpid());
1204        if (!p) {
1205                free(newmsg);
1206                return -1;
1207        }
1208#ifdef SADB_X_EXT_KMADDRESS
1209        p = pfkey_setsadbkmaddr(p, ep, local, remote);
1210        if (!p) {
1211                free(newmsg);
1212                return -1;
1213        }
1214#endif
1215        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
1216        if (!p) {
1217                free(newmsg);
1218                return -1;
1219        }
1220        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
1221        if (!p || p + policylen != ep) {
1222                free(newmsg);
1223                return -1;
1224        }
1225        memcpy(p, policy, policylen);
1226
1227        /* send message */
1228        len = pfkey_send(so, newmsg, len);
1229        free(newmsg);
1230
1231        if (len < 0)
1232                return -1;
1233
1234        __ipsec_errcode = EIPSEC_NO_ERROR;
1235        return len;
1236}
1237#endif
1238
1239
1240/* sending SADB_ADD or SADB_UPDATE message to the kernel */
1241static int
1242pfkey_send_x1(struct pfkey_send_sa_args *sa_parms)
1243{
1244        struct sadb_msg *newmsg;
1245        int len;
1246        caddr_t p;
1247        int plen;
1248        caddr_t ep;
1249
1250        /* validity check */
1251        if (sa_parms->src == NULL || sa_parms->dst == NULL) {
1252                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1253                return -1;
1254        }
1255        if (sa_parms->src->sa_family != sa_parms->dst->sa_family) {
1256                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
1257                return -1;
1258        }
1259        switch (sa_parms->src->sa_family) {
1260        case AF_INET:
1261                plen = sizeof(struct in_addr) << 3;
1262                break;
1263        case AF_INET6:
1264                plen = sizeof(struct in6_addr) << 3;
1265                break;
1266        default:
1267                __ipsec_errcode = EIPSEC_INVAL_FAMILY;
1268                return -1;
1269        }
1270
1271        switch (sa_parms->satype) {
1272        case SADB_SATYPE_ESP:
1273                if (sa_parms->e_type == SADB_EALG_NONE) {
1274                        __ipsec_errcode = EIPSEC_NO_ALGS;
1275                        return -1;
1276                }
1277                break;
1278        case SADB_SATYPE_AH:
1279                if (sa_parms->e_type != SADB_EALG_NONE) {
1280                        __ipsec_errcode = EIPSEC_INVAL_ALGS;
1281                        return -1;
1282                }
1283                if (sa_parms->a_type == SADB_AALG_NONE) {
1284                        __ipsec_errcode = EIPSEC_NO_ALGS;
1285                        return -1;
1286                }
1287                break;
1288        case SADB_X_SATYPE_IPCOMP:
1289                if (sa_parms->e_type == SADB_X_CALG_NONE) {
1290                        __ipsec_errcode = EIPSEC_INVAL_ALGS;
1291                        return -1;
1292                }
1293                if (sa_parms->a_type != SADB_AALG_NONE) {
1294                        __ipsec_errcode = EIPSEC_NO_ALGS;
1295                        return -1;
1296                }
1297                break;
1298#ifdef SADB_X_AALG_TCP_MD5
1299        case SADB_X_SATYPE_TCPSIGNATURE:
1300                if (sa_parms->e_type != SADB_EALG_NONE) {
1301                        __ipsec_errcode = EIPSEC_INVAL_ALGS;
1302                        return -1;
1303                }
1304                if (sa_parms->a_type != SADB_X_AALG_TCP_MD5) {
1305                        __ipsec_errcode = EIPSEC_INVAL_ALGS;
1306                        return -1;
1307                }
1308                break;
1309#endif
1310        default:
1311                __ipsec_errcode = EIPSEC_INVAL_SATYPE;
1312                return -1;
1313        }
1314
1315        /* create new sadb_msg to reply. */
1316        len = sizeof(struct sadb_msg)
1317                + sizeof(struct sadb_sa)
1318                + sizeof(struct sadb_x_sa2)
1319                + sizeof(struct sadb_address)
1320                + PFKEY_ALIGN8(sysdep_sa_len(sa_parms->src))
1321                + sizeof(struct sadb_address)
1322                + PFKEY_ALIGN8(sysdep_sa_len(sa_parms->dst))
1323                + sizeof(struct sadb_lifetime)
1324                + sizeof(struct sadb_lifetime);
1325
1326        if (sa_parms->e_type != SADB_EALG_NONE &&
1327            sa_parms->satype != SADB_X_SATYPE_IPCOMP)
1328                len += (sizeof(struct sadb_key) +
1329                        PFKEY_ALIGN8(sa_parms->e_keylen));
1330        if (sa_parms->a_type != SADB_AALG_NONE)
1331                len += (sizeof(struct sadb_key) +
1332                        PFKEY_ALIGN8(sa_parms->a_keylen));
1333
1334#ifdef SADB_X_EXT_SEC_CTX
1335        if (sa_parms->ctxstr != NULL)
1336                len += (sizeof(struct sadb_x_sec_ctx)
1337                    + PFKEY_ALIGN8(sa_parms->ctxstrlen));
1338#endif
1339
1340#ifdef SADB_X_EXT_NAT_T_TYPE
1341        /* add nat-t packets */
1342        if (sa_parms->l_natt_type) {
1343                switch(sa_parms->satype) {
1344                case SADB_SATYPE_ESP:
1345                case SADB_X_SATYPE_IPCOMP:
1346                        break;
1347                default:
1348                        __ipsec_errcode = EIPSEC_NO_ALGS;
1349                        return -1;
1350                }
1351
1352                len += sizeof(struct sadb_x_nat_t_type);
1353                len += sizeof(struct sadb_x_nat_t_port);
1354                len += sizeof(struct sadb_x_nat_t_port);
1355                if (sa_parms->l_natt_oai)
1356                        len += sizeof(struct sadb_address) +
1357                          PFKEY_ALIGN8(sysdep_sa_len(sa_parms->l_natt_oai));
1358                if (sa_parms->l_natt_oar)
1359                        len += sizeof(struct sadb_address) +
1360                          PFKEY_ALIGN8(sysdep_sa_len(sa_parms->l_natt_oar));
1361#ifdef SADB_X_EXT_NAT_T_FRAG
1362                if (sa_parms->l_natt_frag)
1363                        len += sizeof(struct sadb_x_nat_t_frag);
1364#endif
1365        }
1366#endif
1367
1368        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
1369                __ipsec_set_strerror(strerror(errno));
1370                return -1;
1371        }
1372        ep = ((caddr_t)(void *)newmsg) + len;
1373
1374        p = pfkey_setsadbmsg((void *)newmsg, ep, sa_parms->type, (u_int)len,
1375                             sa_parms->satype, sa_parms->seq, getpid());
1376        if (!p) {
1377                free(newmsg);
1378                return -1;
1379        }
1380        p = pfkey_setsadbsa(p, ep, sa_parms->spi, sa_parms->wsize,
1381                            sa_parms->a_type, sa_parms->e_type,
1382                            sa_parms->flags);
1383        if (!p) {
1384                free(newmsg);
1385                return -1;
1386        }
1387        p = pfkey_setsadbxsa2(p, ep, sa_parms->mode, sa_parms->reqid);
1388        if (!p) {
1389                free(newmsg);
1390                return -1;
1391        }
1392        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, sa_parms->src,
1393                              (u_int)plen, IPSEC_ULPROTO_ANY);
1394        if (!p) {
1395                free(newmsg);
1396                return -1;
1397        }
1398        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, sa_parms->dst,
1399                              (u_int)plen, IPSEC_ULPROTO_ANY);
1400        if (!p) {
1401                free(newmsg);
1402                return -1;
1403        }
1404
1405        if (sa_parms->e_type != SADB_EALG_NONE &&
1406            sa_parms->satype != SADB_X_SATYPE_IPCOMP) {
1407                p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_ENCRYPT,
1408                                   sa_parms->keymat, sa_parms->e_keylen);
1409                if (!p) {
1410                        free(newmsg);
1411                        return -1;
1412                }
1413        }
1414        if (sa_parms->a_type != SADB_AALG_NONE) {
1415                p = pfkey_setsadbkey(p, ep, SADB_EXT_KEY_AUTH,
1416                                     sa_parms->keymat + sa_parms->e_keylen,
1417                                     sa_parms->a_keylen);
1418                if (!p) {
1419                        free(newmsg);
1420                        return -1;
1421                }
1422        }
1423
1424        /* set sadb_lifetime for destination */
1425        p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
1426                        sa_parms->l_alloc, sa_parms->l_bytes,
1427                        sa_parms->l_addtime, sa_parms->l_usetime);
1428        if (!p) {
1429                free(newmsg);
1430                return -1;
1431        }
1432        p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_SOFT,
1433                                  sa_parms->l_alloc, sa_parms->l_bytes,
1434                                  sa_parms->l_addtime, sa_parms->l_usetime);
1435        if (!p) {
1436                free(newmsg);
1437                return -1;
1438        }
1439#ifdef SADB_X_EXT_SEC_CTX
1440        if (sa_parms->ctxstr != NULL) {
1441                p = pfkey_setsecctx(p, ep, SADB_X_EXT_SEC_CTX, sa_parms->ctxdoi,
1442                                    sa_parms->ctxalg, sa_parms->ctxstr,
1443                                    sa_parms->ctxstrlen);
1444                if (!p) {
1445                        free(newmsg);
1446                        return -1;
1447                }
1448        }
1449#endif
1450
1451#ifdef SADB_X_EXT_NAT_T_TYPE
1452        /* Add nat-t messages */
1453        if (sa_parms->l_natt_type) {
1454                p = pfkey_set_natt_type(p, ep, SADB_X_EXT_NAT_T_TYPE,
1455                                        sa_parms->l_natt_type);
1456                if (!p) {
1457                        free(newmsg);
1458                        return -1;
1459                }
1460
1461                p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_SPORT,
1462                                        sa_parms->l_natt_sport);
1463                if (!p) {
1464                        free(newmsg);
1465                        return -1;
1466                }
1467
1468                p = pfkey_set_natt_port(p, ep, SADB_X_EXT_NAT_T_DPORT,
1469                                        sa_parms->l_natt_dport);
1470                if (!p) {
1471                        free(newmsg);
1472                        return -1;
1473                }
1474
1475                if (sa_parms->l_natt_oai) {
1476                        p = pfkey_setsadbaddr(p, ep, SADB_X_EXT_NAT_T_OAI,
1477                                              sa_parms->l_natt_oai,
1478                                              (u_int)PFKEY_ALIGN8(sysdep_sa_len(sa_parms->l_natt_oai)),
1479                                              IPSEC_ULPROTO_ANY);
1480                        if (!p) {
1481                                free(newmsg);
1482                                return -1;
1483                        }
1484                }
1485
1486                if (sa_parms->l_natt_oar) {
1487                        p = pfkey_setsadbaddr(p, ep, SADB_X_EXT_NAT_T_OAR,
1488                                              sa_parms->l_natt_oar,
1489                                              (u_int)PFKEY_ALIGN8(sysdep_sa_len(sa_parms->l_natt_oar)),
1490                                              IPSEC_ULPROTO_ANY);
1491                        if (!p) {
1492                                free(newmsg);
1493                                return -1;
1494                        }
1495                }
1496
1497#ifdef SADB_X_EXT_NAT_T_FRAG
1498                if (sa_parms->l_natt_frag) {
1499                        p = pfkey_set_natt_frag(p, ep, SADB_X_EXT_NAT_T_FRAG,
1500                                        sa_parms->l_natt_frag);
1501                        if (!p) {
1502                                free(newmsg);
1503                                return -1;
1504                        }
1505                }
1506#endif
1507        }
1508#endif
1509
1510        if (p != ep) {
1511                free(newmsg);
1512                return -1;
1513        }
1514
1515        /* send message */
1516        len = pfkey_send(sa_parms->so, newmsg, len);
1517        free(newmsg);
1518
1519        if (len < 0)
1520                return -1;
1521
1522        __ipsec_errcode = EIPSEC_NO_ERROR;
1523        return len;
1524}
1525
1526/* sending SADB_DELETE or SADB_GET message to the kernel */
1527/*ARGSUSED*/
1528static int
1529pfkey_send_x2(int so, u_int type, u_int satype, u_int mode,
1530    struct sockaddr *src, struct sockaddr *dst, u_int32_t spi)
1531{
1532        struct sadb_msg *newmsg;
1533        int len;
1534        caddr_t p;
1535        int plen;
1536        caddr_t ep;
1537
1538        /* validity check */
1539        if (src == NULL || dst == NULL) {
1540                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1541                return -1;
1542        }
1543        if (src->sa_family != dst->sa_family) {
1544                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
1545                return -1;
1546        }
1547        switch (src->sa_family) {
1548        case AF_INET:
1549                plen = sizeof(struct in_addr) << 3;
1550                break;
1551        case AF_INET6:
1552                plen = sizeof(struct in6_addr) << 3;
1553                break;
1554        default:
1555                __ipsec_errcode = EIPSEC_INVAL_FAMILY;
1556                return -1;
1557        }
1558
1559        /* create new sadb_msg to reply. */
1560        len = sizeof(struct sadb_msg)
1561                + sizeof(struct sadb_sa)
1562                + sizeof(struct sadb_address)
1563                + PFKEY_ALIGN8(sysdep_sa_len(src))
1564                + sizeof(struct sadb_address)
1565                + PFKEY_ALIGN8(sysdep_sa_len(dst));
1566
1567        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
1568                __ipsec_set_strerror(strerror(errno));
1569                return -1;
1570        }
1571        ep = ((caddr_t)(void *)newmsg) + len;
1572
1573        p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, satype, 0,
1574            getpid());
1575        if (!p) {
1576                free(newmsg);
1577                return -1;
1578        }
1579        p = pfkey_setsadbsa(p, ep, spi, 0, 0, 0, 0);
1580        if (!p) {
1581                free(newmsg);
1582                return -1;
1583        }
1584        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, (u_int)plen,
1585            IPSEC_ULPROTO_ANY);
1586        if (!p) {
1587                free(newmsg);
1588                return -1;
1589        }
1590        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, (u_int)plen,
1591            IPSEC_ULPROTO_ANY);
1592        if (!p || p != ep) {
1593                free(newmsg);
1594                return -1;
1595        }
1596
1597        /* send message */
1598        len = pfkey_send(so, newmsg, len);
1599        free(newmsg);
1600
1601        if (len < 0)
1602                return -1;
1603
1604        __ipsec_errcode = EIPSEC_NO_ERROR;
1605        return len;
1606}
1607
1608/*
1609 * sending SADB_REGISTER, SADB_FLUSH, SADB_DUMP or SADB_X_PROMISC message
1610 * to the kernel
1611 */
1612static int
1613pfkey_send_x3(int so, u_int type, u_int satype)
1614{
1615        struct sadb_msg *newmsg;
1616        int len;
1617        caddr_t p;
1618        caddr_t ep;
1619
1620        /* validity check */
1621        switch (type) {
1622        case SADB_X_PROMISC:
1623                if (satype != 0 && satype != 1) {
1624                        __ipsec_errcode = EIPSEC_INVAL_SATYPE;
1625                        return -1;
1626                }
1627                break;
1628        default:
1629                switch (satype) {
1630                case SADB_SATYPE_UNSPEC:
1631                case SADB_SATYPE_AH:
1632                case SADB_SATYPE_ESP:
1633                case SADB_X_SATYPE_IPCOMP:
1634#ifdef SADB_X_SATYPE_TCPSIGNATURE
1635                case SADB_X_SATYPE_TCPSIGNATURE:
1636#endif
1637                        break;
1638                default:
1639                        __ipsec_errcode = EIPSEC_INVAL_SATYPE;
1640                        return -1;
1641                }
1642        }
1643
1644        /* create new sadb_msg to send. */
1645        len = sizeof(struct sadb_msg);
1646
1647        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
1648                __ipsec_set_strerror(strerror(errno));
1649                return -1;
1650        }
1651        ep = ((caddr_t)(void *)newmsg) + len;
1652
1653        p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len, satype, 0,
1654            getpid());
1655        if (!p || p != ep) {
1656                free(newmsg);
1657                return -1;
1658        }
1659
1660        /* send message */
1661        len = pfkey_send(so, newmsg, len);
1662        free(newmsg);
1663
1664        if (len < 0)
1665                return -1;
1666
1667        __ipsec_errcode = EIPSEC_NO_ERROR;
1668        return len;
1669}
1670
1671/* sending SADB_X_SPDADD message to the kernel */
1672static int
1673pfkey_send_x4(int so, u_int type, struct sockaddr *src, u_int prefs,
1674    struct sockaddr *dst, u_int prefd, u_int proto, u_int64_t ltime,
1675    u_int64_t vtime, char *policy, int policylen, u_int32_t seq)
1676{
1677        struct sadb_msg *newmsg;
1678        int len;
1679        caddr_t p;
1680        int plen;
1681        caddr_t ep;
1682
1683        /* validity check */
1684        if (src == NULL || dst == NULL) {
1685                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
1686                return -1;
1687        }
1688        if (src->sa_family != dst->sa_family) {
1689                __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
1690                return -1;
1691        }
1692
1693        switch (src->sa_family) {
1694        case AF_INET:
1695                plen = sizeof(struct in_addr) << 3;
1696                break;
1697        case AF_INET6:
1698                plen = sizeof(struct in6_addr) << 3;
1699                break;
1700        default:
1701                __ipsec_errcode = EIPSEC_INVAL_FAMILY;
1702                return -1;
1703        }
1704        if (prefs > plen || prefd > plen) {
1705                __ipsec_errcode = EIPSEC_INVAL_PREFIXLEN;
1706                return -1;
1707        }
1708
1709        /* create new sadb_msg to reply. */
1710        len = sizeof(struct sadb_msg)
1711                + sizeof(struct sadb_address)
1712                + PFKEY_ALIGN8(sysdep_sa_len(src))
1713                + sizeof(struct sadb_address)
1714                + PFKEY_ALIGN8(sysdep_sa_len(src))
1715                + sizeof(struct sadb_lifetime)
1716                + policylen;
1717
1718        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
1719                __ipsec_set_strerror(strerror(errno));
1720                return -1;
1721        }
1722        ep = ((caddr_t)(void *)newmsg) + len;
1723
1724        p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len,
1725            SADB_SATYPE_UNSPEC, seq, getpid());
1726        if (!p) {
1727                free(newmsg);
1728                return -1;
1729        }
1730        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_SRC, src, prefs, proto);
1731        if (!p) {
1732                free(newmsg);
1733                return -1;
1734        }
1735        p = pfkey_setsadbaddr(p, ep, SADB_EXT_ADDRESS_DST, dst, prefd, proto);
1736        if (!p) {
1737                free(newmsg);
1738                return -1;
1739        }
1740        p = pfkey_setsadblifetime(p, ep, SADB_EXT_LIFETIME_HARD,
1741                        0, 0, (u_int)ltime, (u_int)vtime);
1742        if (!p || p + policylen != ep) {
1743                free(newmsg);
1744                return -1;
1745        }
1746        memcpy(p, policy, (size_t)policylen);
1747
1748        /* send message */
1749        len = pfkey_send(so, newmsg, len);
1750        free(newmsg);
1751
1752        if (len < 0)
1753                return -1;
1754
1755        __ipsec_errcode = EIPSEC_NO_ERROR;
1756        return len;
1757}
1758
1759/* sending SADB_X_SPDGET or SADB_X_SPDDELETE message to the kernel */
1760static int
1761pfkey_send_x5(int so, u_int type, u_int32_t spid)
1762{
1763        struct sadb_msg *newmsg;
1764        struct sadb_x_policy xpl;
1765        int len;
1766        caddr_t p;
1767        caddr_t ep;
1768
1769        /* create new sadb_msg to reply. */
1770        len = sizeof(struct sadb_msg)
1771                + sizeof(xpl);
1772
1773        if ((newmsg = CALLOC((size_t)len, struct sadb_msg *)) == NULL) {
1774                __ipsec_set_strerror(strerror(errno));
1775                return -1;
1776        }
1777        ep = ((caddr_t)(void *)newmsg) + len;
1778
1779        p = pfkey_setsadbmsg((void *)newmsg, ep, type, (u_int)len,
1780            SADB_SATYPE_UNSPEC, 0, getpid());
1781        if (!p) {
1782                free(newmsg);
1783                return -1;
1784        }
1785
1786        if (p + sizeof(xpl) != ep) {
1787                free(newmsg);
1788                return -1;
1789        }
1790        memset(&xpl, 0, sizeof(xpl));
1791        xpl.sadb_x_policy_len = PFKEY_UNIT64(sizeof(xpl));
1792        xpl.sadb_x_policy_exttype = SADB_X_EXT_POLICY;
1793        xpl.sadb_x_policy_id = spid;
1794        memcpy(p, &xpl, sizeof(xpl));
1795
1796        /* send message */
1797        len = pfkey_send(so, newmsg, len);
1798        free(newmsg);
1799
1800        if (len < 0)
1801                return -1;
1802
1803        __ipsec_errcode = EIPSEC_NO_ERROR;
1804        return len;
1805}
1806
1807/*
1808 * open a socket.
1809 * OUT:
1810 *      -1: fail.
1811 *      others : success and return value of socket.
1812 */
1813int
1814pfkey_open(void)
1815{
1816        int so;
1817        int bufsiz_current, bufsiz_wanted;
1818        int ret;
1819        socklen_t len;
1820
1821        if ((so = socket(PF_KEY, SOCK_RAW, PF_KEY_V2)) < 0) {
1822                __ipsec_set_strerror(strerror(errno));
1823                return -1;
1824        }
1825
1826        /*
1827         * This is a temporary workaround for KAME PR 154.
1828         * Don't really care even if it fails.
1829         */
1830        /* Try to have 128k. If we have more, do not lower it. */
1831        bufsiz_wanted = 128 * 1024;
1832        len = sizeof(bufsiz_current);
1833        ret = getsockopt(so, SOL_SOCKET, SO_SNDBUF,
1834                &bufsiz_current, &len);
1835        if ((ret < 0) || (bufsiz_current < bufsiz_wanted))
1836                (void)setsockopt(so, SOL_SOCKET, SO_SNDBUF,
1837                        &bufsiz_wanted, sizeof(bufsiz_wanted));
1838
1839        /* Try to have have at least 2MB. If we have more, do not lower it. */
1840        bufsiz_wanted = 2 * 1024 * 1024;
1841        len = sizeof(bufsiz_current);
1842        ret = getsockopt(so, SOL_SOCKET, SO_RCVBUF,
1843                &bufsiz_current, &len);
1844        if (ret < 0)
1845                bufsiz_current = 128 * 1024;
1846
1847        for (; bufsiz_wanted > bufsiz_current; bufsiz_wanted /= 2) {
1848                if (setsockopt(so, SOL_SOCKET, SO_RCVBUF,
1849                                &bufsiz_wanted, sizeof(bufsiz_wanted)) == 0)
1850                        break;
1851        }
1852
1853        __ipsec_errcode = EIPSEC_NO_ERROR;
1854        return so;
1855}
1856
1857int
1858pfkey_set_buffer_size(int so, int size)
1859{
1860        int newsize;
1861        int actual_bufsiz;
1862        socklen_t sizebufsiz;
1863        int desired_bufsiz;
1864
1865        /*
1866         * on linux you may need to allow the kernel to allocate
1867         * more buffer space by increasing:
1868         * /proc/sys/net/core/rmem_max and wmem_max
1869         */
1870        if (size > 0) {
1871                actual_bufsiz = 0;
1872                sizebufsiz = sizeof(actual_bufsiz);
1873                desired_bufsiz = size * 1024;
1874                if ((getsockopt(so, SOL_SOCKET, SO_RCVBUF,
1875                                &actual_bufsiz, &sizebufsiz) < 0)
1876                    || (actual_bufsiz < desired_bufsiz)) {
1877                        if (setsockopt(so, SOL_SOCKET, SO_RCVBUF,
1878                                       &desired_bufsiz, sizeof(desired_bufsiz)) < 0) {
1879                                __ipsec_set_strerror(strerror(errno));
1880                                return -1;
1881                        }
1882                }
1883        }
1884
1885        /* return actual buffer size */
1886        actual_bufsiz = 0;
1887        sizebufsiz = sizeof(actual_bufsiz);
1888        getsockopt(so, SOL_SOCKET, SO_RCVBUF,
1889                   &actual_bufsiz, &sizebufsiz);
1890        return actual_bufsiz / 1024;
1891}
1892
1893/*
1894 * close a socket.
1895 * OUT:
1896 *       0: success.
1897 *      -1: fail.
1898 */
1899void
1900pfkey_close(int so)
1901{
1902        (void)close(so);
1903
1904        __ipsec_errcode = EIPSEC_NO_ERROR;
1905        return;
1906}
1907
1908/*
1909 * receive sadb_msg data, and return pointer to new buffer allocated.
1910 * Must free this buffer later.
1911 * OUT:
1912 *      NULL    : error occured.
1913 *      others  : a pointer to sadb_msg structure.
1914 *
1915 * XXX should be rewritten to pass length explicitly
1916 */
1917struct sadb_msg *
1918pfkey_recv(int so)
1919{
1920        struct sadb_msg buf, *newmsg;
1921        int len, reallen;
1922
1923        while ((len = recv(so, (void *)&buf, sizeof(buf), MSG_PEEK)) < 0) {
1924                if (errno == EINTR)
1925                        continue;
1926                __ipsec_set_strerror(strerror(errno));
1927                return NULL;
1928        }
1929
1930        if (len < sizeof(buf)) {
1931                recv(so, (void *)&buf, sizeof(buf), 0);
1932                __ipsec_errcode = EIPSEC_MAX;
1933                return NULL;
1934        }
1935
1936        /* read real message */
1937        reallen = PFKEY_UNUNIT64(buf.sadb_msg_len);
1938        if ((newmsg = CALLOC((size_t)reallen, struct sadb_msg *)) == 0) {
1939                __ipsec_set_strerror(strerror(errno));
1940                return NULL;
1941        }
1942
1943        while ((len = recv(so, (void *)newmsg, (socklen_t)reallen, 0)) < 0) {
1944                if (errno == EINTR)
1945                        continue;
1946                __ipsec_set_strerror(strerror(errno));
1947                free(newmsg);
1948                return NULL;
1949        }
1950
1951        if (len != reallen) {
1952                __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
1953                free(newmsg);
1954                return NULL;
1955        }
1956
1957        /* don't trust what the kernel says, validate! */
1958        if (PFKEY_UNUNIT64(newmsg->sadb_msg_len) != len) {
1959                __ipsec_errcode = EIPSEC_SYSTEM_ERROR;
1960                free(newmsg);
1961                return NULL;
1962        }
1963
1964        __ipsec_errcode = EIPSEC_NO_ERROR;
1965        return newmsg;
1966}
1967
1968/*
1969 * send message to a socket.
1970 * OUT:
1971 *       others: success and return length sent.
1972 *      -1     : fail.
1973 */
1974int
1975pfkey_send(int so, struct sadb_msg *msg, int len)
1976{
1977        if ((len = send(so, (void *)msg, (socklen_t)len, 0)) < 0) {
1978                __ipsec_set_strerror(strerror(errno));
1979                return -1;
1980        }
1981
1982        __ipsec_errcode = EIPSEC_NO_ERROR;
1983        return len;
1984}
1985
1986/*
1987 * %%% Utilities
1988 * NOTE: These functions are derived from netkey/key.c in KAME.
1989 */
1990/*
1991 * set the pointer to each header in this message buffer.
1992 * IN:  msg: pointer to message buffer.
1993 *      mhp: pointer to the buffer initialized like below:
1994 *              caddr_t mhp[SADB_EXT_MAX + 1];
1995 * OUT: -1: invalid.
1996 *       0: valid.
1997 *
1998 * XXX should be rewritten to obtain length explicitly
1999 */
2000int
2001pfkey_align(struct sadb_msg *msg, caddr_t *mhp)
2002{
2003        struct sadb_ext *ext;
2004        int i;
2005        caddr_t p;
2006        caddr_t ep;     /* XXX should be passed from upper layer */
2007
2008        /* validity check */
2009        if (msg == NULL || mhp == NULL) {
2010                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
2011                return -1;
2012        }
2013
2014        /* initialize */
2015        for (i = 0; i < SADB_EXT_MAX + 1; i++)
2016                mhp[i] = NULL;
2017
2018        mhp[0] = (void *)msg;
2019
2020        /* initialize */
2021        p = (void *) msg;
2022        ep = p + PFKEY_UNUNIT64(msg->sadb_msg_len);
2023
2024        /* skip base header */
2025        p += sizeof(struct sadb_msg);
2026
2027        while (p < ep) {
2028                ext = (void *)p;
2029                if (ep < p + sizeof(*ext) || PFKEY_EXTLEN(ext) < sizeof(*ext) ||
2030                    ep < p + PFKEY_EXTLEN(ext)) {
2031                        /* invalid format */
2032                        break;
2033                }
2034
2035                /* duplicate check */
2036                /* XXX Are there duplication either KEY_AUTH or KEY_ENCRYPT ?*/
2037                if (mhp[ext->sadb_ext_type] != NULL) {
2038                        __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
2039                        return -1;
2040                }
2041
2042                /* set pointer */
2043                switch (ext->sadb_ext_type) {
2044                case SADB_EXT_SA:
2045                case SADB_EXT_LIFETIME_CURRENT:
2046                case SADB_EXT_LIFETIME_HARD:
2047                case SADB_EXT_LIFETIME_SOFT:
2048                case SADB_EXT_ADDRESS_SRC:
2049                case SADB_EXT_ADDRESS_DST:
2050                case SADB_EXT_ADDRESS_PROXY:
2051                case SADB_EXT_KEY_AUTH:
2052                        /* XXX should to be check weak keys. */
2053                case SADB_EXT_KEY_ENCRYPT:
2054                        /* XXX should to be check weak keys. */
2055                case SADB_EXT_IDENTITY_SRC:
2056                case SADB_EXT_IDENTITY_DST:
2057                case SADB_EXT_SENSITIVITY:
2058                case SADB_EXT_PROPOSAL:
2059                case SADB_EXT_SUPPORTED_AUTH:
2060                case SADB_EXT_SUPPORTED_ENCRYPT:
2061                case SADB_EXT_SPIRANGE:
2062                case SADB_X_EXT_POLICY:
2063                case SADB_X_EXT_SA2:
2064#ifdef SADB_X_EXT_NAT_T_TYPE
2065                case SADB_X_EXT_NAT_T_TYPE:
2066                case SADB_X_EXT_NAT_T_SPORT:
2067                case SADB_X_EXT_NAT_T_DPORT:
2068                case SADB_X_EXT_NAT_T_OAI:
2069                case SADB_X_EXT_NAT_T_OAR:
2070#endif
2071#ifdef SADB_X_EXT_TAG
2072                case SADB_X_EXT_TAG:
2073#endif
2074#ifdef SADB_X_EXT_PACKET
2075                case SADB_X_EXT_PACKET:
2076#endif
2077#ifdef SADB_X_EXT_KMADDRESS
2078                case SADB_X_EXT_KMADDRESS:
2079#endif
2080#ifdef SADB_X_EXT_SEC_CTX
2081                case SADB_X_EXT_SEC_CTX:
2082#endif
2083                        mhp[ext->sadb_ext_type] = (void *)ext;
2084                        break;
2085                default:
2086                        __ipsec_errcode = EIPSEC_INVAL_EXTTYPE;
2087                        return -1;
2088                }
2089
2090                p += PFKEY_EXTLEN(ext);
2091        }
2092
2093        if (p != ep) {
2094                __ipsec_errcode = EIPSEC_INVAL_SADBMSG;
2095                return -1;
2096        }
2097
2098        __ipsec_errcode = EIPSEC_NO_ERROR;
2099        return 0;
2100}
2101
2102/*
2103 * check basic usage for sadb_msg,
2104 * NOTE: This routine is derived from netkey/key.c in KAME.
2105 * IN:  msg: pointer to message buffer.
2106 *      mhp: pointer to the buffer initialized like below:
2107 *
2108 *              caddr_t mhp[SADB_EXT_MAX + 1];
2109 *
2110 * OUT: -1: invalid.
2111 *       0: valid.
2112 */
2113int
2114pfkey_check(caddr_t *mhp)
2115{
2116        struct sadb_msg *msg;
2117
2118        /* validity check */
2119        if (mhp == NULL || mhp[0] == NULL) {
2120                __ipsec_errcode = EIPSEC_INVAL_ARGUMENT;
2121                return -1;
2122        }
2123
2124        msg = (void *)mhp[0];
2125
2126        /* check version */
2127        if (msg->sadb_msg_version != PF_KEY_V2) {
2128                __ipsec_errcode = EIPSEC_INVAL_VERSION;
2129                return -1;
2130        }
2131
2132        /* check type */
2133        if (msg->sadb_msg_type > SADB_MAX) {
2134                __ipsec_errcode = EIPSEC_INVAL_MSGTYPE;
2135                return -1;
2136        }
2137
2138        /* check SA type */
2139        switch (msg->sadb_msg_satype) {
2140        case SADB_SATYPE_UNSPEC:
2141                switch (msg->sadb_msg_type) {
2142                case SADB_GETSPI:
2143                case SADB_UPDATE:
2144                case SADB_ADD:
2145                case SADB_DELETE:
2146                case SADB_GET:
2147                case SADB_ACQUIRE:
2148                case SADB_EXPIRE:
2149#ifdef SADB_X_NAT_T_NEW_MAPPING
2150                case SADB_X_NAT_T_NEW_MAPPING:
2151#endif
2152                        __ipsec_errcode = EIPSEC_INVAL_SATYPE;
2153                        return -1;
2154                }
2155                break;
2156        case SADB_SATYPE_ESP:
2157        case SADB_SATYPE_AH:
2158        case SADB_X_SATYPE_IPCOMP:
2159#ifdef SADB_X_SATYPE_TCPSIGNATURE
2160        case SADB_X_SATYPE_TCPSIGNATURE:
2161#endif
2162                switch (msg->sadb_msg_type) {
2163                case SADB_X_SPDADD:
2164                case SADB_X_SPDDELETE:
2165                case SADB_X_SPDGET:
2166                case SADB_X_SPDDUMP:
2167                case SADB_X_SPDFLUSH:
2168                        __ipsec_errcode = EIPSEC_INVAL_SATYPE;
2169                        return -1;
2170                }
2171#ifdef SADB_X_NAT_T_NEW_MAPPING
2172                if (msg->sadb_msg_type == SADB_X_NAT_T_NEW_MAPPING &&
2173                    msg->sadb_msg_satype != SADB_SATYPE_ESP) {
2174                        __ipsec_errcode = EIPSEC_INVAL_SATYPE;
2175                        return -1;
2176                }
2177#endif
2178                break;
2179        case SADB_SATYPE_RSVP:
2180        case SADB_SATYPE_OSPFV2:
2181        case SADB_SATYPE_RIPV2:
2182        case SADB_SATYPE_MIP:
2183                __ipsec_errcode = EIPSEC_NOT_SUPPORTED;
2184                return -1;
2185        case 1: /* XXX: What does it do ? */
2186                if (msg->sadb_msg_type == SADB_X_PROMISC)
2187                        break;
2188                /*FALLTHROUGH*/
2189        default:
2190#ifdef __linux__
2191                /* Linux kernel seems to be buggy and return
2192                 * uninitialized satype for spd flush message */
2193                if (msg->sadb_msg_type == SADB_X_SPDFLUSH)
2194                        break;
2195#endif
2196                __ipsec_errcode = EIPSEC_INVAL_SATYPE;
2197                return -1;
2198        }
2199
2200        /* check field of upper layer protocol and address family */
2201        if (mhp[SADB_EXT_ADDRESS_SRC] != NULL
2202         && mhp[SADB_EXT_ADDRESS_DST] != NULL) {
2203                struct sadb_address *src0, *dst0;
2204
2205                src0 = (void *)(mhp[SADB_EXT_ADDRESS_SRC]);
2206                dst0 = (void *)(mhp[SADB_EXT_ADDRESS_DST]);
2207
2208                if (src0->sadb_address_proto != dst0->sadb_address_proto) {
2209                        __ipsec_errcode = EIPSEC_PROTO_MISMATCH;
2210                        return -1;
2211                }
2212
2213                if (PFKEY_ADDR_SADDR(src0)->sa_family
2214                 != PFKEY_ADDR_SADDR(dst0)->sa_family) {
2215                        __ipsec_errcode = EIPSEC_FAMILY_MISMATCH;
2216                        return -1;
2217                }
2218
2219                switch (PFKEY_ADDR_SADDR(src0)->sa_family) {
2220                case AF_INET:
2221                case AF_INET6:
2222                        break;
2223                default:
2224                        __ipsec_errcode = EIPSEC_INVAL_FAMILY;
2225                        return -1;
2226                }
2227
2228                /*
2229                 * prefixlen == 0 is valid because there must be the case
2230                 * all addresses are matched.
2231                 */
2232        }
2233
2234        __ipsec_errcode = EIPSEC_NO_ERROR;
2235        return 0;
2236}
2237
2238/*
2239 * set data into sadb_msg.
2240 * `buf' must has been allocated sufficiently.
2241 */
2242static caddr_t
2243pfkey_setsadbmsg(caddr_t buf, caddr_t lim, u_int type, u_int tlen,
2244    u_int satype, u_int32_t seq, pid_t pid)
2245{
2246        struct sadb_msg *p;
2247        u_int len;
2248
2249        p = (void *)buf;
2250        len = sizeof(struct sadb_msg);
2251
2252        if (buf + len > lim)
2253                return NULL;
2254
2255        memset(p, 0, len);
2256        p->sadb_msg_version = PF_KEY_V2;
2257        p->sadb_msg_type = type;
2258        p->sadb_msg_errno = 0;
2259        p->sadb_msg_satype = satype;
2260        p->sadb_msg_len = PFKEY_UNIT64(tlen);
2261        p->sadb_msg_reserved = 0;
2262        p->sadb_msg_seq = seq;
2263        p->sadb_msg_pid = (u_int32_t)pid;
2264
2265        return(buf + len);
2266}
2267
2268/*
2269 * copy secasvar data into sadb_address.
2270 * `buf' must has been allocated sufficiently.
2271 */
2272static caddr_t
2273pfkey_setsadbsa(caddr_t buf, caddr_t lim, u_int32_t spi, u_int wsize,
2274    u_int auth, u_int enc, u_int32_t flags)
2275{
2276        struct sadb_sa *p;
2277        u_int len;
2278
2279        p = (void *)buf;
2280        len = sizeof(struct sadb_sa);
2281
2282        if (buf + len > lim)
2283                return NULL;
2284
2285        memset(p, 0, len);
2286        p->sadb_sa_len = PFKEY_UNIT64(len);
2287        p->sadb_sa_exttype = SADB_EXT_SA;
2288        p->sadb_sa_spi = spi;
2289        p->sadb_sa_replay = wsize;
2290        p->sadb_sa_state = SADB_SASTATE_LARVAL;
2291        p->sadb_sa_auth = auth;
2292        p->sadb_sa_encrypt = enc;
2293        p->sadb_sa_flags = flags;
2294
2295        return(buf + len);
2296}
2297
2298/*
2299 * set data into sadb_address.
2300 * `buf' must has been allocated sufficiently.
2301 * prefixlen is in bits.
2302 */
2303static caddr_t
2304pfkey_setsadbaddr(caddr_t buf, caddr_t lim, u_int exttype,
2305    struct sockaddr *saddr, u_int prefixlen, u_int ul_proto)
2306{
2307        struct sadb_address *p;
2308        u_int len;
2309
2310        p = (void *)buf;
2311        len = sizeof(struct sadb_address) + PFKEY_ALIGN8(sysdep_sa_len(saddr));
2312
2313        if (buf + len > lim)
2314                return NULL;
2315
2316        memset(p, 0, len);
2317        p->sadb_address_len = PFKEY_UNIT64(len);
2318        p->sadb_address_exttype = exttype & 0xffff;
2319        p->sadb_address_proto = ul_proto & 0xff;
2320        p->sadb_address_prefixlen = prefixlen;
2321        p->sadb_address_reserved = 0;
2322
2323        memcpy(p + 1, saddr, (size_t)sysdep_sa_len(saddr));
2324
2325        return(buf + len);
2326}
2327
2328#ifdef SADB_X_EXT_KMADDRESS
2329/*
2330 * set data into sadb_x_kmaddress.
2331 * `buf' must has been allocated sufficiently.
2332 */
2333static caddr_t
2334pfkey_setsadbkmaddr(caddr_t buf, caddr_t lim, struct sockaddr *local,
2335    struct sockaddr *remote)
2336{
2337        struct sadb_x_kmaddress *p;
2338        struct sockaddr *sa;
2339        u_int salen = sysdep_sa_len(local);
2340        u_int len;
2341
2342        /* sanity check */
2343        if (local->sa_family != remote->sa_family)
2344                return NULL;
2345
2346        p = (void *)buf;
2347        len = sizeof(struct sadb_x_kmaddress) + PFKEY_ALIGN8(2*salen);
2348
2349        if (buf + len > lim)
2350                return NULL;
2351
2352        memset(p, 0, len);
2353        p->sadb_x_kmaddress_len = PFKEY_UNIT64(len);
2354        p->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS;
2355        p->sadb_x_kmaddress_reserved = 0;
2356        sa = (struct sockaddr *)(p + 1);
2357        memcpy(sa, local, salen);
2358        sa = (struct sockaddr *)((char *)sa + salen);
2359        memcpy(sa, remote, salen);
2360
2361        return(buf + len);
2362}
2363#endif
2364
2365/*
2366 * set sadb_key structure after clearing buffer with zero.
2367 * OUT: the pointer of buf + len.
2368 */
2369static caddr_t
2370pfkey_setsadbkey(caddr_t buf, caddr_t lim, u_int type, caddr_t key,
2371    u_int keylen)
2372{
2373        struct sadb_key *p;
2374        u_int len;
2375
2376        p = (void *)buf;
2377        len = sizeof(struct sadb_key) + PFKEY_ALIGN8(keylen);
2378
2379        if (buf + len > lim)
2380                return NULL;
2381
2382        memset(p, 0, len);
2383        p->sadb_key_len = PFKEY_UNIT64(len);
2384        p->sadb_key_exttype = type;
2385        p->sadb_key_bits = keylen << 3;
2386        p->sadb_key_reserved = 0;
2387
2388        memcpy(p + 1, key, keylen);
2389
2390        return buf + len;
2391}
2392
2393/*
2394 * set sadb_lifetime structure after clearing buffer with zero.
2395 * OUT: the pointer of buf + len.
2396 */
2397static caddr_t
2398pfkey_setsadblifetime(caddr_t buf, caddr_t lim, u_int type, u_int32_t l_alloc,
2399    u_int32_t l_bytes, u_int32_t l_addtime, u_int32_t l_usetime)
2400{
2401        struct sadb_lifetime *p;
2402        u_int len;
2403
2404        p = (void *)buf;
2405        len = sizeof(struct sadb_lifetime);
2406
2407        if (buf + len > lim)
2408                return NULL;
2409
2410        memset(p, 0, len);
2411        p->sadb_lifetime_len = PFKEY_UNIT64(len);
2412        p->sadb_lifetime_exttype = type;
2413
2414        switch (type) {
2415        case SADB_EXT_LIFETIME_SOFT:
2416                p->sadb_lifetime_allocations
2417                        = (l_alloc * soft_lifetime_allocations_rate) /100;
2418                p->sadb_lifetime_bytes
2419                        = (l_bytes * soft_lifetime_bytes_rate) /100;
2420                p->sadb_lifetime_addtime
2421                        = (l_addtime * soft_lifetime_addtime_rate) /100;
2422                p->sadb_lifetime_usetime
2423                        = (l_usetime * soft_lifetime_usetime_rate) /100;
2424                break;
2425        case SADB_EXT_LIFETIME_HARD:
2426                p->sadb_lifetime_allocations = l_alloc;
2427                p->sadb_lifetime_bytes = l_bytes;
2428                p->sadb_lifetime_addtime = l_addtime;
2429                p->sadb_lifetime_usetime = l_usetime;
2430                break;
2431        }
2432
2433        return buf + len;
2434}
2435
2436/*
2437 * copy secasvar data into sadb_address.
2438 * `buf' must has been allocated sufficiently.
2439 */
2440static caddr_t
2441pfkey_setsadbxsa2(caddr_t buf, caddr_t lim, u_int32_t mode0, u_int32_t reqid)
2442{
2443        struct sadb_x_sa2 *p;
2444        u_int8_t mode = mode0 & 0xff;
2445        u_int len;
2446
2447        p = (void *)buf;
2448        len = sizeof(struct sadb_x_sa2);
2449
2450        if (buf + len > lim)
2451                return NULL;
2452
2453        memset(p, 0, len);
2454        p->sadb_x_sa2_len = PFKEY_UNIT64(len);
2455        p->sadb_x_sa2_exttype = SADB_X_EXT_SA2;
2456        p->sadb_x_sa2_mode = mode;
2457        p->sadb_x_sa2_reqid = reqid;
2458
2459        return(buf + len);
2460}
2461
2462#ifdef SADB_X_EXT_NAT_T_TYPE
2463static caddr_t
2464pfkey_set_natt_type(caddr_t buf, caddr_t lim, u_int type, u_int8_t l_natt_type)
2465{
2466        struct sadb_x_nat_t_type *p;
2467        u_int len;
2468
2469        p = (void *)buf;
2470        len = sizeof(struct sadb_x_nat_t_type);
2471
2472        if (buf + len > lim)
2473                return NULL;
2474
2475        memset(p, 0, len);
2476        p->sadb_x_nat_t_type_len = PFKEY_UNIT64(len);
2477        p->sadb_x_nat_t_type_exttype = type;
2478        p->sadb_x_nat_t_type_type = l_natt_type;
2479
2480        return(buf + len);
2481}
2482
2483static caddr_t
2484pfkey_set_natt_port(caddr_t buf, caddr_t lim, u_int type, u_int16_t l_natt_port)
2485{
2486        struct sadb_x_nat_t_port *p;
2487        u_int len;
2488
2489        p = (void *)buf;
2490        len = sizeof(struct sadb_x_nat_t_port);
2491
2492        if (buf + len > lim)
2493                return NULL;
2494
2495        memset(p, 0, len);
2496        p->sadb_x_nat_t_port_len = PFKEY_UNIT64(len);
2497        p->sadb_x_nat_t_port_exttype = type;
2498        p->sadb_x_nat_t_port_port = htons(l_natt_port);
2499
2500        return(buf + len);
2501}
2502#endif
2503
2504#ifdef SADB_X_EXT_NAT_T_FRAG
2505static caddr_t
2506pfkey_set_natt_frag(caddr_t buf, caddr_t lim, u_int type,
2507    u_int16_t l_natt_frag)
2508{
2509        struct sadb_x_nat_t_frag *p;
2510        u_int len;
2511
2512        p = (void *)buf;
2513        len = sizeof(struct sadb_x_nat_t_frag);
2514
2515        if (buf + len > lim)
2516                return NULL;
2517
2518        memset(p, 0, len);
2519        p->sadb_x_nat_t_frag_len = PFKEY_UNIT64(len);
2520        p->sadb_x_nat_t_frag_exttype = type;
2521        p->sadb_x_nat_t_frag_fraglen = l_natt_frag;
2522
2523        return(buf + len);
2524}
2525#endif
2526
2527#ifdef SADB_X_EXT_SEC_CTX
2528static caddr_t
2529pfkey_setsecctx(caddr_t buf, caddr_t lim, u_int type, u_int8_t ctx_doi,
2530    u_int8_t ctx_alg, caddr_t sec_ctx, u_int16_t sec_ctxlen)
2531{
2532        struct sadb_x_sec_ctx *p;
2533        u_int len;
2534
2535        p = (struct sadb_x_sec_ctx *)buf;
2536        len = sizeof(struct sadb_x_sec_ctx) + PFKEY_ALIGN8(sec_ctxlen);
2537
2538        if (buf + len > lim)
2539                return NULL;
2540
2541        memset(p, 0, len);
2542        p->sadb_x_sec_len = PFKEY_UNIT64(len);
2543        p->sadb_x_sec_exttype = type;
2544        p->sadb_x_ctx_len = sec_ctxlen;
2545        p->sadb_x_ctx_doi = ctx_doi;
2546        p->sadb_x_ctx_alg = ctx_alg;
2547
2548        memcpy(p + 1, sec_ctx, sec_ctxlen);
2549
2550        return buf + len;
2551}
2552#endif
2553
2554/*
2555 * Deprecated, available for backward compatibility with third party
2556 * libipsec users. Please use pfkey_send_update2 and pfkey_send_add2 instead
2557 */
2558int
2559pfkey_send_update(int so, u_int satype, u_int mode, struct sockaddr *src,
2560    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
2561    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
2562    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
2563    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq)
2564{
2565        struct pfkey_send_sa_args psaa;
2566
2567        memset(&psaa, 0, sizeof(psaa));
2568        psaa.so = so;
2569        psaa.type = SADB_UPDATE;
2570        psaa.satype = satype;
2571        psaa.mode = mode;
2572        psaa.wsize = wsize;
2573        psaa.src = src;
2574        psaa.dst = dst;
2575        psaa.spi = spi;
2576        psaa.reqid = reqid;
2577        psaa.keymat = keymat;
2578        psaa.e_type = e_type;
2579        psaa.e_keylen = e_keylen;
2580        psaa.a_type = a_type;
2581        psaa.a_keylen = a_keylen;
2582        psaa.flags = flags;
2583        psaa.l_alloc = l_alloc;
2584        psaa.l_bytes = l_bytes;
2585        psaa.l_addtime = l_addtime;
2586        psaa.l_usetime = l_usetime;
2587        psaa.seq = seq;
2588
2589        return pfkey_send_update2(&psaa);
2590}
2591
2592int
2593pfkey_send_update_nat(int so, u_int satype, u_int mode, struct sockaddr *src,
2594    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
2595    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
2596    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
2597    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq,
2598    u_int8_t l_natt_type, u_int16_t l_natt_sport, u_int16_t l_natt_dport,
2599    struct sockaddr *l_natt_oa, u_int16_t l_natt_frag)
2600{
2601        struct pfkey_send_sa_args psaa;
2602
2603        memset(&psaa, 0, sizeof(psaa));
2604        psaa.so = so;
2605        psaa.type = SADB_UPDATE;
2606        psaa.satype = satype;
2607        psaa.mode = mode;
2608        psaa.wsize = wsize;
2609        psaa.src = src;
2610        psaa.dst = dst;
2611        psaa.spi = spi;
2612        psaa.reqid = reqid;
2613        psaa.keymat = keymat;
2614        psaa.e_type = e_type;
2615        psaa.e_keylen = e_keylen;
2616        psaa.a_type = a_type;
2617        psaa.a_keylen = a_keylen;
2618        psaa.flags = flags;
2619        psaa.l_alloc = l_alloc;
2620        psaa.l_bytes = l_bytes;
2621        psaa.l_addtime = l_addtime;
2622        psaa.l_usetime = l_usetime;
2623        psaa.seq = seq;
2624        psaa.l_natt_type = l_natt_type;
2625        psaa.l_natt_sport = l_natt_sport;
2626        psaa.l_natt_dport = l_natt_dport;
2627        psaa.l_natt_oar = l_natt_oa;
2628        psaa.l_natt_frag = l_natt_frag;
2629
2630        return pfkey_send_update2(&psaa);
2631}
2632
2633int
2634pfkey_send_add(int so, u_int satype, u_int mode, struct sockaddr *src,
2635    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
2636    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
2637    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
2638    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq)
2639{
2640        struct pfkey_send_sa_args psaa;
2641
2642        memset(&psaa, 0, sizeof(psaa));
2643        psaa.so = so;
2644        psaa.type = SADB_ADD;
2645        psaa.satype = satype;
2646        psaa.mode = mode;
2647        psaa.wsize = wsize;
2648        psaa.src = src;
2649        psaa.dst = dst;
2650        psaa.spi = spi;
2651        psaa.reqid = reqid;
2652        psaa.keymat = keymat;
2653        psaa.e_type = e_type;
2654        psaa.e_keylen = e_keylen;
2655        psaa.a_type = a_type;
2656        psaa.a_keylen = a_keylen;
2657        psaa.flags = flags;
2658        psaa.l_alloc = l_alloc;
2659        psaa.l_bytes = l_bytes;
2660        psaa.l_addtime = l_addtime;
2661        psaa.l_usetime = l_usetime;
2662        psaa.seq = seq;
2663
2664        return pfkey_send_add2(&psaa);
2665}
2666
2667int
2668pfkey_send_add_nat(int so, u_int satype, u_int mode, struct sockaddr *src,
2669    struct sockaddr *dst, u_int32_t spi, u_int32_t reqid, u_int wsize,
2670    caddr_t keymat, u_int e_type, u_int e_keylen, u_int a_type,
2671    u_int a_keylen, u_int flags, u_int32_t l_alloc, u_int64_t l_bytes,
2672    u_int64_t l_addtime, u_int64_t l_usetime, u_int32_t seq,
2673    u_int8_t l_natt_type, u_int16_t l_natt_sport, u_int16_t l_natt_dport,
2674    struct sockaddr *l_natt_oa, u_int16_t l_natt_frag)
2675{
2676        struct pfkey_send_sa_args psaa;
2677
2678        memset(&psaa, 0, sizeof(psaa));
2679        psaa.so = so;
2680        psaa.type = SADB_ADD;
2681        psaa.satype = satype;
2682        psaa.mode = mode;
2683        psaa.wsize = wsize;
2684        psaa.src = src;
2685        psaa.dst = dst;
2686        psaa.spi = spi;
2687        psaa.reqid = reqid;
2688        psaa.keymat = keymat;
2689        psaa.e_type = e_type;
2690        psaa.e_keylen = e_keylen;
2691        psaa.a_type = a_type;
2692        psaa.a_keylen = a_keylen;
2693        psaa.flags = flags;
2694        psaa.l_alloc = l_alloc;
2695        psaa.l_bytes = l_bytes;
2696        psaa.l_addtime = l_addtime;
2697        psaa.l_usetime = l_usetime;
2698        psaa.seq = seq;
2699        psaa.l_natt_type = l_natt_type;
2700        psaa.l_natt_sport = l_natt_sport;
2701        psaa.l_natt_dport = l_natt_dport;
2702        psaa.l_natt_oai = l_natt_oa;
2703        psaa.l_natt_frag = l_natt_frag;
2704
2705        return pfkey_send_add2(&psaa);
2706}
Note: See TracBrowser for help on using the repository browser.