]>
Commit | Line | Data |
---|---|---|
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 | ||
53 | typedef struct private_reset_seq_t private_reset_seq_t; | |
54 | ||
55 | /** | |
56 | * Private data of an reset_seq_t object. | |
57 | */ | |
58 | struct 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 | ||
76 | typedef struct reset_cb_data_t reset_cb_data_t; | |
77 | ||
78 | /** | |
79 | * Data needed for the callback job | |
80 | */ | |
81 | struct 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 | 97 | static 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 | */ | |
157 | static 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 | ||
182 | METHOD(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 | ||
194 | METHOD(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 | */ | |
203 | hook_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__ */ |