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