Annotation of embedaddon/strongswan/src/conftest/hooks/reset_seq.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2010 Martin Willi
                      3:  * Copyright (C) 2010 revosec AG
                      4:  *
                      5:  * This program is free software; you can redistribute it and/or modify it
                      6:  * under the terms of the GNU General Public License as published by the
                      7:  * Free Software Foundation; either version 2 of the License, or (at your
                      8:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                      9:  *
                     10:  * This program is distributed in the hope that it will be useful, but
                     11:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     12:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     13:  * for more details.
                     14:  */
                     15: /*
                     16:  * Copyright (C) 2012 achelos GmbH
                     17:  *
                     18:  * Permission is hereby granted, free of charge, to any person obtaining a copy
                     19:  * of this software and associated documentation files (the "Software"), to deal
                     20:  * in the Software without restriction, including without limitation the rights
                     21:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
                     22:  * copies of the Software, and to permit persons to whom the Software is
                     23:  * furnished to do so, subject to the following conditions:
                     24:  *
                     25:  * The above copyright notice and this permission notice shall be included in
                     26:  * all copies or substantial portions of the Software.
                     27:  *
                     28:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
                     29:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
                     30:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
                     31:  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
                     32:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
                     33:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
                     34:  * THE SOFTWARE.
                     35:  */
                     36: 
                     37: #include "hook.h"
                     38: 
                     39: /* this hook is currently only supported on Linux (systems like FreeBSD don't
                     40:  * actually provide an interface to change the sequence numbers of SAs) */
                     41: #ifdef __linux__
                     42: 
                     43: #include <linux/xfrm.h>
                     44: #include <unistd.h>
                     45: #include <errno.h>
                     46: 
                     47: #include <processing/jobs/callback_job.h>
                     48: #include <plugins/kernel_netlink/kernel_netlink_shared.h>
                     49: 
                     50: #define XFRM_RTA(nlh, x) ((struct rtattr*)(NLMSG_DATA(nlh) + NLMSG_ALIGN(sizeof(x))))
                     51: 
                     52: typedef struct private_reset_seq_t private_reset_seq_t;
                     53: 
                     54: /**
                     55:  * Private data of an reset_seq_t object.
                     56:  */
                     57: struct private_reset_seq_t {
                     58: 
                     59:        /**
                     60:         * Implements the hook_t interface.
                     61:         */
                     62:        hook_t hook;
                     63: 
                     64:        /**
                     65:         * Delay for reset
                     66:         */
                     67:        int delay;
                     68: 
                     69:        /**
                     70:         * Sequence number to set for outgoing packages
                     71:         */
                     72:        int oseq;
                     73: };
                     74: 
                     75: typedef struct reset_cb_data_t reset_cb_data_t;
                     76: 
                     77: /**
                     78:  * Data needed for the callback job
                     79:  */
                     80: struct reset_cb_data_t {
                     81: 
                     82:        /**
                     83:         * The SA to modify
                     84:         */
                     85:        struct xfrm_usersa_id usersa;
                     86: 
                     87:        /**
                     88:         * Sequence number to set for outgoing packages
                     89:         */
                     90:        int oseq;
                     91: };
                     92: 
                     93: /**
                     94:  * Callback job
                     95:  */
                     96: static job_requeue_t reset_cb(struct reset_cb_data_t *data)
                     97: {
                     98:        netlink_buf_t request;
                     99:        struct nlmsghdr *hdr;
                    100:        struct xfrm_aevent_id *id;
                    101:        struct rtattr *rthdr;
                    102:        struct xfrm_replay_state *rpstate;
                    103:        struct sockaddr_nl addr;
                    104:        int s, len;
                    105: 
                    106:        DBG1(DBG_CFG, "setting sequence number of SPI 0x%x to %d",
                    107:                 htonl(data->usersa.spi), data->oseq);
                    108: 
                    109:        memset(&request, 0, sizeof(request));
                    110: 
                    111:        hdr = &request.hdr;
                    112:        hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_REPLACE;
                    113:        hdr->nlmsg_seq = 201;
                    114:        hdr->nlmsg_pid = getpid();
                    115:        hdr->nlmsg_type = XFRM_MSG_NEWAE;
                    116:        hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct xfrm_aevent_id));
                    117: 
                    118:        id = (struct xfrm_aevent_id*)NLMSG_DATA(hdr);
                    119:        id->sa_id = data->usersa;
                    120: 
                    121:        rthdr = XFRM_RTA(hdr, struct xfrm_aevent_id);
                    122:        rthdr->rta_type = XFRMA_REPLAY_VAL;
                    123:        rthdr->rta_len = RTA_LENGTH(sizeof(struct xfrm_replay_state));
                    124:        hdr->nlmsg_len += rthdr->rta_len;
                    125: 
                    126:        /* xfrm_replay_state is the structure the kernel uses for
                    127:         * replay detection, and the oseq element contains the
                    128:         * sequence number for outgoing packets. Currently, this
                    129:         * function sets the other elements seq (records the number of
                    130:         * incoming packets) and bitmask to zero, but they could be
                    131:         * adjusted in the same way as oseq if required. */
                    132:        rpstate = (struct xfrm_replay_state*)RTA_DATA(rthdr);
                    133:        rpstate->oseq = data->oseq;
                    134: 
                    135:        s = socket(AF_NETLINK, SOCK_RAW, NETLINK_XFRM);
                    136:        if (s == -1)
                    137:        {
                    138:                DBG1(DBG_CFG, "opening XFRM socket failed: %s", strerror(errno));
                    139:                return JOB_REQUEUE_NONE;
                    140:        }
                    141:        memset(&addr, 0, sizeof(addr));
                    142:        addr.nl_family = AF_NETLINK;
                    143:        len = sendto(s, hdr, hdr->nlmsg_len, 0,
                    144:                                 (struct sockaddr*)&addr, sizeof(addr));
                    145:        if (len != hdr->nlmsg_len)
                    146:        {
                    147:                DBG1(DBG_CFG, "sending XFRM aevent failed: %s", strerror(errno));
                    148:        }
                    149:        close(s);
                    150:        return JOB_REQUEUE_NONE;
                    151: }
                    152: 
                    153: /**
                    154:  * Schedule sequence number reset job
                    155:  */
                    156: static void schedule_reset_job(private_reset_seq_t *this, host_t *dst,
                    157:                                                           uint32_t spi)
                    158: {
                    159:        struct reset_cb_data_t *data;
                    160:        chunk_t chunk;
                    161: 
                    162:        INIT(data,
                    163:                .usersa = {
                    164:                        .spi = spi,
                    165:                        .family = dst->get_family(dst),
                    166:                        .proto = IPPROTO_ESP,
                    167:                },
                    168:                .oseq = this->oseq,
                    169:        );
                    170: 
                    171:        chunk = dst->get_address(dst);
                    172:        memcpy(&data->usersa.daddr, chunk.ptr,
                    173:                   min(chunk.len, sizeof(xfrm_address_t)));
                    174: 
                    175:        lib->scheduler->schedule_job(lib->scheduler,
                    176:                                                                 (job_t*)callback_job_create(
                    177:                                                                        (void*)reset_cb, data, (void*)free, NULL),
                    178:                                                                 this->delay);
                    179: }
                    180: 
                    181: METHOD(listener_t, child_updown, bool,
                    182:        private_reset_seq_t *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
                    183:        bool up)
                    184: {
                    185:        if (up)
                    186:        {
                    187:                schedule_reset_job(this, ike_sa->get_other_host(ike_sa),
                    188:                                                   child_sa->get_spi(child_sa, FALSE));
                    189:        }
                    190:        return TRUE;
                    191: }
                    192: 
                    193: METHOD(hook_t, destroy, void,
                    194:        private_reset_seq_t *this)
                    195: {
                    196:        free(this);
                    197: }
                    198: 
                    199: /**
                    200:  * Create the IKE_AUTH fill hook
                    201:  */
                    202: hook_t *reset_seq_hook_create(char *name)
                    203: {
                    204:        private_reset_seq_t *this;
                    205: 
                    206:        INIT(this,
                    207:                .hook = {
                    208:                        .listener = {
                    209:                                .child_updown = _child_updown,
                    210:                        },
                    211:                        .destroy = _destroy,
                    212:                },
                    213:                .delay = conftest->test->get_int(conftest->test,
                    214:                                                                                "hooks.%s.delay", 10, name),
                    215:                .oseq = conftest->test->get_int(conftest->test,
                    216:                                                                                "hooks.%s.oseq", 0, name),
                    217:        );
                    218: 
                    219:        return &this->hook;
                    220: }
                    221: 
                    222: #endif /* __linux__ */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>