1: /*-
2: * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3: *
4: * Copyright (c) 2022 Michael Pounov <misho@elwix.org>, CloudSigma AG
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: */
27: #include "fwsync.h"
28:
29:
30: static void
31: fwsync_edge_proc(void *arg)
32: {
33: int e, rcvflg = 0;
34: struct uio uio;
35: struct mbuf *m = NULL;
36: struct fws_proto *pkt;
37:
38: DTRACE();
39:
40: callout_schedule(&fws_co, hz);
41:
42: memset(&uio, 0, sizeof uio);
43: uio.uio_resid = 1000000000;
44: uio.uio_td = curthread;
45:
46: if ((fws_cfg.cfg.on & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
47: rcvflg = MSG_DONTWAIT;
48: e = soreceive(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], NULL, &uio, &m, NULL, &rcvflg);
49: if (e) {
50: if (e != EAGAIN)
51: printf("error in edge handler #%d\n", e);
52: return;
53: }
54: pkt = mtod(m, struct fws_proto*);
55: if (m_length(m, NULL) != sizeof(struct fws_proto)) {
56: printf("FWSync packet length=%d isn't match expected %lu\n",
57: m_length(m, NULL), sizeof(struct fws_proto));
58: m_freem(m);
59: return;
60: }
61:
62: switch (pkt->fws_version) {
63: case FWS_PKTVER_STATE:
64: fwsync_add_state(pkt);
65: break;
66: case FWS_PKTVER_ALIAS:
67: fwsync_add_alias(pkt);
68: break;
69: default:
70: printf("FWSync packet was discarded due to wrong version\n");
71: break;
72: }
73:
74: m_freem(m);
75: }
76: }
77:
78: int
79: fwsync_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
80: {
81: ipfw_obj_header *oh;
82: struct ipfw_sync_cfg *ucfg;
83: size_t sz;
84: int e;
85:
86: DTRACE();
87:
88: sz = sizeof(*oh) + sizeof(*ucfg);
89: /* Check minimum header size */
90: if (sd->valsize < sz)
91: return (EINVAL);
92:
93: oh = (ipfw_obj_header*) sd->kbuf;
94:
95: /* Basic length checks for TLVs */
96: if (oh->ntlv.head.length != sizeof(oh->ntlv))
97: return (EINVAL);
98:
99: ucfg = (struct ipfw_sync_cfg*) (oh + 1);
100:
101: /* Check if name is properly terminated */
102: if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
103: return (EINVAL);
104:
105: if (ucfg->mode == CFG_SYNC_EDGE && !fws_cfg.cfg.edge && !(fws_ctx.config & CTX_CFG_EDGE) &&
106: !strcmp(ucfg->name, "edge") && ucfg->addrs == 1) {
107: fws_cfg.cfg.edge = 1;
108: memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE], &ucfg->addr[CFG_SYNC_ADDR_EDGE],
109: sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE]);
110: fws_ctx.config |= CTX_CFG_EDGE;
111:
112: e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE].addr.sa_family == AF_INET) ? AF_INET : AF_INET6,
113: &fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
114: if (e) {
115: printf("fwsync edge socreate failed #%d\n", e);
116: return e;
117: }
118:
119: e = sobind(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], &fws_cfg.cfg_addr[CFG_SYNC_ADDR_EDGE].addr, curthread);
120: if (e) {
121: if (e != EADDRINUSE)
122: printf("fwsync edge sobind failed #%d\n", e);
123: else
124: printf("fwsync edge address in use!\n");
125: return e;
126: } else
127: fws_ctx.config |= CTX_EDGE_READY;
128: } else if (ucfg->mode == CFG_SYNC_COLLECTOR && !(fws_ctx.config & CTX_CFG_COLLECTOR_1) &&
129: !strcmp(ucfg->name, "collector") && ucfg->addrs > 0 && ucfg->addrs < 3) {
130: fws_cfg.cfg.collector = 1;
131: fws_cfg.cfg.addrs = ucfg->addrs;
132: memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1], &ucfg->addr[CFG_SYNC_ADDR_COLLECTOR_1],
133: sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1]);
134:
135: fws_ctx.config |= CTX_CFG_COLLECTOR_1;
136:
137: e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_1].addr.sa_family == AF_INET) ? AF_INET : AF_INET6,
138: &fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_1], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
139: if (e) {
140: printf("fwsync collector %d socreate failed #%d\n", e, CFG_SYNC_ADDR_COLLECTOR_1);
141: return e;
142: } else
143: fws_ctx.config |= CTX_COLLECTOR_1_READY;
144:
145: if (fws_cfg.cfg.addrs > 1) {
146: memcpy(&fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2], &ucfg->addr[CFG_SYNC_ADDR_COLLECTOR_2],
147: sizeof fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2]);
148:
149: fws_ctx.config |= CTX_CFG_COLLECTOR_2;
150:
151: e = socreate((fws_cfg.cfg_addr[CFG_SYNC_ADDR_COLLECTOR_2].addr.sa_family == AF_INET) ? AF_INET : AF_INET6,
152: &fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_2], SOCK_DGRAM, IPPROTO_UDP, curthread->td_ucred, curthread);
153: if (e) {
154: printf("fwsync collector %d socreate failed #%d\n", e, CFG_SYNC_ADDR_COLLECTOR_2);
155: return e;
156: } else
157: fws_ctx.config |= CTX_COLLECTOR_2_READY;
158: }
159: } else
160: return (EINVAL);
161:
162: return 0;
163: }
164:
165: int
166: fwsync_destroy(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
167: {
168: int *n;
169: ipfw_obj_header *oh;
170: size_t sz;
171:
172: DTRACE();
173:
174: sz = sizeof(*oh) + sizeof(int);
175: /* Check minimum header size */
176: if (sd->valsize < sz)
177: return (EINVAL);
178:
179: oh = (ipfw_obj_header*) sd->kbuf;
180:
181: /* Basic length checks for TLVs */
182: if (oh->ntlv.head.length != sizeof(oh->ntlv))
183: return (EINVAL);
184:
185: n = (int*) (oh + 1);
186: if (*n & CFG_SYNC_EDGE) {
187: fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
188: fws_cfg.cfg.edge = 0;
189: fws_cfg.cfg.addrs = 0;
190: memset(fws_cfg.cfg_addr, 0, sizeof fws_cfg.cfg_addr[0]);
191:
192: if (fws_ctx.config & CTX_EDGE_ONLINE) {
193: callout_drain(&fws_co);
194: ipfw_unregister_state_sync();
195: ipfw_unregister_alias_sync();
196: soshutdown(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE], SHUT_RD);
197: soclose(fws_ctx.sockz[CFG_SYNC_ADDR_EDGE]);
198: }
199: }
200: if (*n & CFG_SYNC_COLLECTOR) {
201: if (fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE)) {
202: ipfw_unregister_state_hook();
203: ipfw_unregister_alias_hook();
204: }
205:
206: taskqueue_drain(fws_tq, &fws_sndpkt_task);
207:
208: fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
209: fws_cfg.cfg.collector = 0;
210: fws_cfg.cfg.addrs = 0;
211: memset(fws_cfg.cfg_addr + 1, 0, sizeof fws_cfg.cfg_addr[0] * 2);
212:
213: if (fws_ctx.config & CTX_COLLECTOR_2_READY)
214: soclose(fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_2]);
215: if (fws_ctx.config & CTX_COLLECTOR_1_READY)
216: soclose(fws_ctx.sockz[CFG_SYNC_ADDR_COLLECTOR_1]);
217: }
218:
219: fws_ctx.config ^= fws_ctx.config;
220:
221: return 0;
222: }
223:
224: int
225: fwsync_get_cfg(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
226: {
227: ipfw_obj_header *oh;
228: struct ipfw_sync_cfg *ucfg;
229: size_t sz;
230:
231: DTRACE();
232:
233: sz = sizeof(*oh) + sizeof(*ucfg);
234: /* Check minimum header size */
235: if (sd->valsize < sz)
236: return (EINVAL);
237:
238: oh = (struct _ipfw_obj_header*) ipfw_get_sopt_header(sd, sz);
239:
240: /* Basic length checks for TLVs */
241: if (oh->ntlv.head.length != sizeof(oh->ntlv))
242: return (EINVAL);
243:
244: ucfg = (struct ipfw_sync_cfg*) (oh + 1);
245:
246: /* Check if name is properly terminated */
247: if (strnlen(ucfg->name, sizeof(ucfg->name)) == sizeof(ucfg->name))
248: return (EINVAL);
249:
250: snprintf(ucfg->name, sizeof ucfg->name, "%d", fws_cfg.cfg.on);
251: ucfg->mode = 0;
252: if (fws_cfg.cfg.edge)
253: ucfg->mode |= CFG_SYNC_EDGE;
254: if (fws_cfg.cfg.collector)
255: ucfg->mode |= CFG_SYNC_COLLECTOR;
256: ucfg->addrs = (fws_cfg.cfg.addrs != 1) ? fws_cfg.cfg.addrs : 1;
257: memcpy(ucfg->addr, fws_cfg.cfg_addr, sizeof ucfg->addr);
258:
259: return 0;
260: }
261:
262: int
263: fwsync_list(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
264: {
265: DTRACE();
266:
267: return 0;
268: }
269:
270: int
271: fwsync_start(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
272: {
273: int *n;
274: ipfw_obj_header *oh;
275: size_t sz;
276:
277: DTRACE();
278:
279: sz = sizeof(*oh) + sizeof(int);
280: /* Check minimum header size */
281: if (sd->valsize < sz)
282: return (EINVAL);
283:
284: oh = (ipfw_obj_header*) sd->kbuf;
285:
286: /* Basic length checks for TLVs */
287: if (oh->ntlv.head.length != sizeof(oh->ntlv))
288: return (EINVAL);
289:
290: n = (int*) (oh + 1);
291:
292: if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_EDGE_READY)) {
293: fws_cfg.cfg.on |= CFG_SYNC_EDGE;
294:
295: callout_reset(&fws_co, hz, fwsync_edge_proc, NULL);
296:
297: if (!(fws_ctx.config & CTX_EDGE_ONLINE)) {
298: ipfw_register_state_sync(fwsync_state_sync);
299: ipfw_register_alias_sync(fwsync_alias_sync);
300: }
301:
302: fws_ctx.config |= CTX_EDGE_ONLINE;
303: }
304:
305: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_READY)) {
306: fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
307:
308: if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
309: ipfw_register_state_hook(fwsync_state_handler);
310: ipfw_register_alias_hook(fwsync_alias_handler);
311: }
312:
313: fws_ctx.config |= CTX_COLLECTOR_1_ONLINE;
314: }
315:
316: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_READY)) {
317: fws_cfg.cfg.on |= CFG_SYNC_COLLECTOR;
318:
319: if (!(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
320: ipfw_register_state_hook(fwsync_state_handler);
321: ipfw_register_alias_hook(fwsync_alias_handler);
322: }
323:
324: fws_ctx.config |= CTX_COLLECTOR_2_ONLINE;
325: }
326:
327: return 0;
328: }
329:
330: int
331: fwsync_stop(struct ip_fw_chain *ch, ip_fw3_opheader *op3, struct sockopt_data *sd)
332: {
333: int *n;
334: ipfw_obj_header *oh;
335: size_t sz;
336:
337: DTRACE();
338:
339: sz = sizeof(*oh) + sizeof(int);
340: /* Check minimum header size */
341: if (sd->valsize < sz)
342: return (EINVAL);
343:
344: oh = (ipfw_obj_header*) sd->kbuf;
345:
346: /* Basic length checks for TLVs */
347: if (oh->ntlv.head.length != sizeof(oh->ntlv))
348: return (EINVAL);
349:
350: n = (int*) (oh + 1);
351:
352: if ((*n & CFG_SYNC_EDGE) && (fws_ctx.config & CTX_CFG_EDGE)) {
353: fws_cfg.cfg.on &= ~CFG_SYNC_EDGE;
354: fws_ctx.config &= ~CTX_EDGE_ONLINE;
355:
356: callout_drain(&fws_co);
357:
358: ipfw_unregister_state_sync();
359: ipfw_unregister_alias_sync();
360: }
361:
362: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_2_ONLINE))
363: fws_ctx.config &= ~CTX_COLLECTOR_2_ONLINE;
364: if ((*n & CFG_SYNC_COLLECTOR) && (fws_ctx.config & CTX_COLLECTOR_1_ONLINE))
365: fws_ctx.config &= ~CTX_COLLECTOR_1_ONLINE;
366:
367: if ((*n & CFG_SYNC_COLLECTOR) &&
368: !(fws_ctx.config & (CTX_COLLECTOR_1_ONLINE | CTX_COLLECTOR_2_ONLINE))) {
369: fws_cfg.cfg.on &= ~CFG_SYNC_COLLECTOR;
370:
371: ipfw_unregister_state_hook();
372: ipfw_unregister_alias_hook();
373:
374: taskqueue_drain(fws_tq, &fws_sndpkt_task);
375: }
376:
377: return 0;
378: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>