Line data Source code
1 : /* $OpenBSD: if_pflow.c,v 1.90 2018/07/30 12:22:14 mpi Exp $ */
2 :
3 : /*
4 : * Copyright (c) 2011 Florian Obser <florian@narrans.de>
5 : * Copyright (c) 2011 Sebastian Benoit <benoit-lists@fb12.de>
6 : * Copyright (c) 2008 Henning Brauer <henning@openbsd.org>
7 : * Copyright (c) 2008 Joerg Goltermann <jg@osn.de>
8 : *
9 : * Permission to use, copy, modify, and distribute this software for any
10 : * purpose with or without fee is hereby granted, provided that the above
11 : * copyright notice and this permission notice appear in all copies.
12 : *
13 : * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 : * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 : * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 : * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 : * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
18 : * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19 : * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 : */
21 :
22 : #include <sys/param.h>
23 : #include <sys/malloc.h>
24 : #include <sys/systm.h>
25 : #include <sys/mbuf.h>
26 : #include <sys/socket.h>
27 : #include <sys/timeout.h>
28 : #include <sys/ioctl.h>
29 : #include <sys/kernel.h>
30 : #include <sys/socket.h>
31 : #include <sys/socketvar.h>
32 : #include <sys/sysctl.h>
33 :
34 : #include <net/if.h>
35 : #include <net/if_types.h>
36 : #include <net/bpf.h>
37 : #include <net/route.h>
38 : #include <netinet/in.h>
39 : #include <netinet/if_ether.h>
40 : #include <netinet/tcp.h>
41 :
42 : #include <netinet/ip.h>
43 : #include <netinet/ip_var.h>
44 : #include <netinet/udp.h>
45 : #include <netinet/udp_var.h>
46 : #include <netinet/in_pcb.h>
47 :
48 : #include <net/pfvar.h>
49 : #include <net/if_pflow.h>
50 :
51 : #include "bpfilter.h"
52 : #include "pflow.h"
53 :
54 : #define PFLOW_MINMTU \
55 : (sizeof(struct pflow_header) + sizeof(struct pflow_flow))
56 :
57 : #ifdef PFLOWDEBUG
58 : #define DPRINTF(x) do { printf x ; } while (0)
59 : #else
60 : #define DPRINTF(x)
61 : #endif
62 :
63 : SLIST_HEAD(, pflow_softc) pflowif_list;
64 : struct pflowstats pflowstats;
65 :
66 : void pflowattach(int);
67 : int pflow_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
68 : struct rtentry *rt);
69 : void pflow_output_process(void *);
70 : int pflow_clone_create(struct if_clone *, int);
71 : int pflow_clone_destroy(struct ifnet *);
72 : int pflow_set(struct pflow_softc *, struct pflowreq *);
73 : void pflow_init_timeouts(struct pflow_softc *);
74 : int pflow_calc_mtu(struct pflow_softc *, int, int);
75 : void pflow_setmtu(struct pflow_softc *, int);
76 : int pflowvalidsockaddr(const struct sockaddr *, int);
77 : int pflowioctl(struct ifnet *, u_long, caddr_t);
78 :
79 : struct mbuf *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
80 : void pflow_flush(struct pflow_softc *);
81 : int pflow_sendout_v5(struct pflow_softc *);
82 : int pflow_sendout_ipfix(struct pflow_softc *, sa_family_t);
83 : int pflow_sendout_ipfix_tmpl(struct pflow_softc *);
84 : int pflow_sendout_mbuf(struct pflow_softc *, struct mbuf *);
85 : void pflow_timeout(void *);
86 : void pflow_timeout6(void *);
87 : void pflow_timeout_tmpl(void *);
88 : void copy_flow_data(struct pflow_flow *, struct pflow_flow *,
89 : struct pf_state *, struct pf_state_key *, int, int);
90 : void copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *,
91 : struct pflow_ipfix_flow4 *, struct pf_state *, struct pf_state_key *,
92 : struct pflow_softc *, int, int);
93 : void copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *,
94 : struct pflow_ipfix_flow6 *, struct pf_state *, struct pf_state_key *,
95 : struct pflow_softc *, int, int);
96 : int pflow_pack_flow(struct pf_state *, struct pf_state_key *,
97 : struct pflow_softc *);
98 : int pflow_pack_flow_ipfix(struct pf_state *, struct pf_state_key *,
99 : struct pflow_softc *);
100 : int export_pflow_if(struct pf_state*, struct pf_state_key *,
101 : struct pflow_softc *);
102 : int copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
103 : int copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow,
104 : struct pflow_softc *sc);
105 : int copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow,
106 : struct pflow_softc *sc);
107 :
108 : struct if_clone pflow_cloner =
109 : IF_CLONE_INITIALIZER("pflow", pflow_clone_create,
110 : pflow_clone_destroy);
111 :
112 : void
113 0 : pflowattach(int npflow)
114 : {
115 0 : SLIST_INIT(&pflowif_list);
116 0 : if_clone_attach(&pflow_cloner);
117 0 : }
118 :
119 : int
120 0 : pflow_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
121 : struct rtentry *rt)
122 : {
123 0 : m_freem(m); /* drop packet */
124 0 : return (EAFNOSUPPORT);
125 : }
126 :
127 : void
128 0 : pflow_output_process(void *arg)
129 : {
130 0 : struct mbuf_list ml;
131 0 : struct pflow_softc *sc = arg;
132 : struct mbuf *m;
133 :
134 0 : mq_delist(&sc->sc_outputqueue, &ml);
135 0 : KERNEL_LOCK();
136 0 : while ((m = ml_dequeue(&ml)) != NULL) {
137 0 : pflow_sendout_mbuf(sc, m);
138 : }
139 0 : KERNEL_UNLOCK();
140 0 : }
141 :
142 : int
143 0 : pflow_clone_create(struct if_clone *ifc, int unit)
144 : {
145 : struct ifnet *ifp;
146 : struct pflow_softc *pflowif;
147 :
148 0 : pflowif = malloc(sizeof(*pflowif), M_DEVBUF, M_WAITOK|M_ZERO);
149 0 : MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
150 0 : pflowif->sc_version = PFLOW_PROTO_DEFAULT;
151 :
152 : /* ipfix template init */
153 0 : bzero(&pflowif->sc_tmpl_ipfix,sizeof(pflowif->sc_tmpl_ipfix));
154 0 : pflowif->sc_tmpl_ipfix.set_header.set_id =
155 : htons(PFLOW_IPFIX_TMPL_SET_ID);
156 0 : pflowif->sc_tmpl_ipfix.set_header.set_length =
157 : htons(sizeof(struct pflow_ipfix_tmpl));
158 :
159 : /* ipfix IPv4 template */
160 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.tmpl_id =
161 : htons(PFLOW_IPFIX_TMPL_IPV4_ID);
162 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.h.field_count
163 0 : = htons(PFLOW_IPFIX_TMPL_IPV4_FIELD_COUNT);
164 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.field_id =
165 : htons(PFIX_IE_sourceIPv4Address);
166 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_ip.len = htons(4);
167 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.field_id =
168 : htons(PFIX_IE_destinationIPv4Address);
169 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_ip.len = htons(4);
170 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.field_id =
171 : htons(PFIX_IE_ingressInterface);
172 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_in.len = htons(4);
173 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.field_id =
174 : htons(PFIX_IE_egressInterface);
175 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.if_index_out.len = htons(4);
176 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.field_id =
177 : htons(PFIX_IE_packetDeltaCount);
178 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.packets.len = htons(8);
179 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.field_id =
180 : htons(PFIX_IE_octetDeltaCount);
181 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.octets.len = htons(8);
182 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.field_id =
183 : htons(PFIX_IE_flowStartMilliseconds);
184 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.start.len = htons(8);
185 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.field_id =
186 : htons(PFIX_IE_flowEndMilliseconds);
187 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.finish.len = htons(8);
188 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.field_id =
189 : htons(PFIX_IE_sourceTransportPort);
190 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.src_port.len = htons(2);
191 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.field_id =
192 : htons(PFIX_IE_destinationTransportPort);
193 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.dest_port.len = htons(2);
194 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.field_id =
195 : htons(PFIX_IE_ipClassOfService);
196 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.tos.len = htons(1);
197 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.field_id =
198 : htons(PFIX_IE_protocolIdentifier);
199 0 : pflowif->sc_tmpl_ipfix.ipv4_tmpl.protocol.len = htons(1);
200 :
201 : /* ipfix IPv6 template */
202 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.tmpl_id =
203 : htons(PFLOW_IPFIX_TMPL_IPV6_ID);
204 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.h.field_count =
205 : htons(PFLOW_IPFIX_TMPL_IPV6_FIELD_COUNT);
206 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.field_id =
207 : htons(PFIX_IE_sourceIPv6Address);
208 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_ip.len = htons(16);
209 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.field_id =
210 : htons(PFIX_IE_destinationIPv6Address);
211 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_ip.len = htons(16);
212 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.field_id =
213 : htons(PFIX_IE_ingressInterface);
214 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_in.len = htons(4);
215 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.field_id =
216 : htons(PFIX_IE_egressInterface);
217 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.if_index_out.len = htons(4);
218 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.field_id =
219 : htons(PFIX_IE_packetDeltaCount);
220 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.packets.len = htons(8);
221 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.field_id =
222 : htons(PFIX_IE_octetDeltaCount);
223 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.octets.len = htons(8);
224 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.field_id =
225 : htons(PFIX_IE_flowStartMilliseconds);
226 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.start.len = htons(8);
227 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.field_id =
228 : htons(PFIX_IE_flowEndMilliseconds);
229 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.finish.len = htons(8);
230 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.field_id =
231 : htons(PFIX_IE_sourceTransportPort);
232 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.src_port.len = htons(2);
233 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.field_id =
234 : htons(PFIX_IE_destinationTransportPort);
235 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.dest_port.len = htons(2);
236 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.field_id =
237 : htons(PFIX_IE_ipClassOfService);
238 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.tos.len = htons(1);
239 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.field_id =
240 : htons(PFIX_IE_protocolIdentifier);
241 0 : pflowif->sc_tmpl_ipfix.ipv6_tmpl.protocol.len = htons(1);
242 :
243 0 : ifp = &pflowif->sc_if;
244 0 : snprintf(ifp->if_xname, sizeof ifp->if_xname, "pflow%d", unit);
245 0 : ifp->if_softc = pflowif;
246 0 : ifp->if_ioctl = pflowioctl;
247 0 : ifp->if_output = pflow_output;
248 0 : ifp->if_start = NULL;
249 0 : ifp->if_xflags = IFXF_CLONED;
250 0 : ifp->if_type = IFT_PFLOW;
251 0 : IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
252 0 : ifp->if_hdrlen = PFLOW_HDRLEN;
253 0 : ifp->if_flags = IFF_UP;
254 0 : ifp->if_flags &= ~IFF_RUNNING; /* not running, need receiver */
255 0 : mq_init(&pflowif->sc_outputqueue, 8192, IPL_SOFTNET);
256 0 : pflow_setmtu(pflowif, ETHERMTU);
257 0 : pflow_init_timeouts(pflowif);
258 0 : if_attach(ifp);
259 0 : if_alloc_sadl(ifp);
260 :
261 0 : task_set(&pflowif->sc_outputtask, pflow_output_process, pflowif);
262 :
263 : /* Insert into list of pflows */
264 0 : NET_LOCK();
265 0 : SLIST_INSERT_HEAD(&pflowif_list, pflowif, sc_next);
266 0 : NET_UNLOCK();
267 0 : return (0);
268 : }
269 :
270 : int
271 0 : pflow_clone_destroy(struct ifnet *ifp)
272 : {
273 0 : struct pflow_softc *sc = ifp->if_softc;
274 : int error;
275 :
276 : error = 0;
277 :
278 0 : if (timeout_initialized(&sc->sc_tmo))
279 0 : timeout_del(&sc->sc_tmo);
280 0 : if (timeout_initialized(&sc->sc_tmo6))
281 0 : timeout_del(&sc->sc_tmo6);
282 0 : if (timeout_initialized(&sc->sc_tmo_tmpl))
283 0 : timeout_del(&sc->sc_tmo_tmpl);
284 0 : pflow_flush(sc);
285 0 : task_del(net_tq(ifp->if_index), &sc->sc_outputtask);
286 0 : mq_purge(&sc->sc_outputqueue);
287 0 : m_freem(sc->send_nam);
288 0 : if (sc->so != NULL) {
289 0 : error = soclose(sc->so, MSG_DONTWAIT);
290 0 : sc->so = NULL;
291 0 : }
292 0 : if (sc->sc_flowdst != NULL)
293 0 : free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
294 0 : if (sc->sc_flowsrc != NULL)
295 0 : free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
296 0 : if_detach(ifp);
297 0 : NET_LOCK();
298 0 : SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
299 0 : NET_UNLOCK();
300 0 : free(sc, M_DEVBUF, sizeof(*sc));
301 0 : return (error);
302 : }
303 :
304 : int
305 0 : pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port)
306 : {
307 : struct sockaddr_in6 *sin6;
308 : struct sockaddr_in *sin;
309 :
310 0 : if (sa == NULL)
311 0 : return (0);
312 0 : switch(sa->sa_family) {
313 : case AF_INET:
314 0 : sin = (struct sockaddr_in*) sa;
315 0 : return (sin->sin_addr.s_addr != INADDR_ANY &&
316 0 : (ignore_port || sin->sin_port != 0));
317 : case AF_INET6:
318 0 : sin6 = (struct sockaddr_in6*) sa;
319 0 : return (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
320 0 : (ignore_port || sin6->sin6_port != 0));
321 : default:
322 0 : return (0);
323 : }
324 0 : }
325 :
326 : int
327 0 : pflow_set(struct pflow_softc *sc, struct pflowreq *pflowr)
328 : {
329 0 : struct proc *p = curproc;
330 0 : struct socket *so;
331 : struct sockaddr *sa;
332 : int error = 0;
333 :
334 0 : if (pflowr->addrmask & PFLOW_MASK_VERSION) {
335 0 : switch(pflowr->version) {
336 : case PFLOW_PROTO_5:
337 : case PFLOW_PROTO_10:
338 : break;
339 : default:
340 0 : return(EINVAL);
341 : }
342 : }
343 :
344 0 : pflow_flush(sc);
345 :
346 0 : if (pflowr->addrmask & PFLOW_MASK_DSTIP) {
347 0 : if (sc->sc_flowdst != NULL &&
348 0 : sc->sc_flowdst->sa_family != pflowr->flowdst.ss_family) {
349 0 : free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
350 0 : sc->sc_flowdst = NULL;
351 0 : if (sc->so != NULL) {
352 0 : soclose(sc->so, MSG_DONTWAIT);
353 0 : sc->so = NULL;
354 0 : }
355 : }
356 :
357 0 : switch (pflowr->flowdst.ss_family) {
358 : case AF_INET:
359 0 : if (sc->sc_flowdst == NULL) {
360 0 : if ((sc->sc_flowdst = malloc(
361 : sizeof(struct sockaddr_in),
362 0 : M_DEVBUF, M_NOWAIT)) == NULL)
363 0 : return (ENOMEM);
364 : }
365 0 : memcpy(sc->sc_flowdst, &pflowr->flowdst,
366 : sizeof(struct sockaddr_in));
367 0 : sc->sc_flowdst->sa_len = sizeof(struct
368 : sockaddr_in);
369 0 : break;
370 : case AF_INET6:
371 0 : if (sc->sc_flowdst == NULL) {
372 0 : if ((sc->sc_flowdst = malloc(
373 : sizeof(struct sockaddr_in6),
374 0 : M_DEVBUF, M_NOWAIT)) == NULL)
375 0 : return (ENOMEM);
376 : }
377 0 : memcpy(sc->sc_flowdst, &pflowr->flowdst,
378 : sizeof(struct sockaddr_in6));
379 0 : sc->sc_flowdst->sa_len = sizeof(struct
380 : sockaddr_in6);
381 0 : break;
382 : default:
383 : break;
384 : }
385 :
386 0 : if (sc->sc_flowdst != NULL) {
387 0 : sc->send_nam->m_len = sc->sc_flowdst->sa_len;
388 0 : sa = mtod(sc->send_nam, struct sockaddr *);
389 0 : memcpy(sa, sc->sc_flowdst, sc->sc_flowdst->sa_len);
390 0 : }
391 : }
392 :
393 0 : if (pflowr->addrmask & PFLOW_MASK_SRCIP) {
394 0 : if (sc->sc_flowsrc != NULL)
395 0 : free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
396 0 : sc->sc_flowsrc = NULL;
397 0 : if (sc->so != NULL) {
398 0 : soclose(sc->so, MSG_DONTWAIT);
399 0 : sc->so = NULL;
400 0 : }
401 0 : switch(pflowr->flowsrc.ss_family) {
402 : case AF_INET:
403 0 : if ((sc->sc_flowsrc = malloc(
404 : sizeof(struct sockaddr_in),
405 0 : M_DEVBUF, M_NOWAIT)) == NULL)
406 0 : return (ENOMEM);
407 0 : memcpy(sc->sc_flowsrc, &pflowr->flowsrc,
408 : sizeof(struct sockaddr_in));
409 0 : sc->sc_flowsrc->sa_len = sizeof(struct
410 : sockaddr_in);
411 0 : break;
412 : case AF_INET6:
413 0 : if ((sc->sc_flowsrc = malloc(
414 : sizeof(struct sockaddr_in6),
415 0 : M_DEVBUF, M_NOWAIT)) == NULL)
416 0 : return (ENOMEM);
417 0 : memcpy(sc->sc_flowsrc, &pflowr->flowsrc,
418 : sizeof(struct sockaddr_in6));
419 0 : sc->sc_flowsrc->sa_len = sizeof(struct
420 : sockaddr_in6);
421 0 : break;
422 : default:
423 : break;
424 : }
425 : }
426 :
427 0 : if (sc->so == NULL) {
428 0 : if (pflowvalidsockaddr(sc->sc_flowdst, 0)) {
429 0 : error = socreate(sc->sc_flowdst->sa_family,
430 : &so, SOCK_DGRAM, 0);
431 0 : if (error)
432 0 : return (error);
433 0 : if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) {
434 : struct mbuf *m;
435 : int s;
436 :
437 0 : MGET(m, M_WAIT, MT_SONAME);
438 0 : m->m_len = sc->sc_flowsrc->sa_len;
439 0 : sa = mtod(m, struct sockaddr *);
440 0 : memcpy(sa, sc->sc_flowsrc,
441 : sc->sc_flowsrc->sa_len);
442 :
443 0 : s = solock(so);
444 0 : error = sobind(so, m, p);
445 0 : sounlock(so, s);
446 0 : m_freem(m);
447 0 : if (error) {
448 0 : soclose(so, MSG_DONTWAIT);
449 0 : return (error);
450 : }
451 0 : }
452 0 : sc->so = so;
453 0 : }
454 0 : } else if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) {
455 0 : soclose(sc->so, MSG_DONTWAIT);
456 0 : sc->so = NULL;
457 0 : }
458 :
459 : /* error check is above */
460 0 : if (pflowr->addrmask & PFLOW_MASK_VERSION)
461 0 : sc->sc_version = pflowr->version;
462 :
463 0 : pflow_setmtu(sc, ETHERMTU);
464 0 : pflow_init_timeouts(sc);
465 :
466 0 : return (0);
467 0 : }
468 :
469 : int
470 0 : pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
471 : {
472 0 : struct proc *p = curproc;
473 0 : struct pflow_softc *sc = ifp->if_softc;
474 0 : struct ifreq *ifr = (struct ifreq *)data;
475 0 : struct pflowreq pflowr;
476 : int error;
477 :
478 0 : switch (cmd) {
479 : case SIOCSIFADDR:
480 : case SIOCSIFDSTADDR:
481 : case SIOCSIFFLAGS:
482 0 : if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
483 0 : ifp->if_flags |= IFF_RUNNING;
484 0 : sc->sc_gcounter=pflowstats.pflow_flows;
485 : /* send templates on startup */
486 0 : if (sc->sc_version == PFLOW_PROTO_10)
487 0 : pflow_sendout_ipfix_tmpl(sc);
488 : } else
489 0 : ifp->if_flags &= ~IFF_RUNNING;
490 : break;
491 : case SIOCSIFMTU:
492 0 : if (ifr->ifr_mtu < PFLOW_MINMTU)
493 0 : return (EINVAL);
494 0 : if (ifr->ifr_mtu > MCLBYTES)
495 0 : ifr->ifr_mtu = MCLBYTES;
496 0 : if (ifr->ifr_mtu < ifp->if_mtu)
497 0 : pflow_flush(sc);
498 0 : pflow_setmtu(sc, ifr->ifr_mtu);
499 0 : break;
500 :
501 : case SIOCGETPFLOW:
502 0 : bzero(&pflowr, sizeof(pflowr));
503 :
504 0 : if (sc->sc_flowsrc != NULL)
505 0 : memcpy(&pflowr.flowsrc, sc->sc_flowsrc,
506 : sc->sc_flowsrc->sa_len);
507 0 : if (sc->sc_flowdst != NULL)
508 0 : memcpy(&pflowr.flowdst, sc->sc_flowdst,
509 : sc->sc_flowdst->sa_len);
510 0 : pflowr.version = sc->sc_version;
511 :
512 0 : if ((error = copyout(&pflowr, ifr->ifr_data,
513 : sizeof(pflowr))))
514 0 : return (error);
515 : break;
516 :
517 : case SIOCSETPFLOW:
518 0 : if ((error = suser(p)) != 0)
519 0 : return (error);
520 0 : if ((error = copyin(ifr->ifr_data, &pflowr,
521 : sizeof(pflowr))))
522 0 : return (error);
523 :
524 : /* XXXSMP breaks atomicity */
525 0 : NET_UNLOCK();
526 0 : error = pflow_set(sc, &pflowr);
527 0 : NET_LOCK();
528 0 : if (error != 0)
529 0 : return (error);
530 :
531 0 : if ((ifp->if_flags & IFF_UP) && sc->so != NULL) {
532 0 : ifp->if_flags |= IFF_RUNNING;
533 0 : sc->sc_gcounter=pflowstats.pflow_flows;
534 0 : if (sc->sc_version == PFLOW_PROTO_10)
535 0 : pflow_sendout_ipfix_tmpl(sc);
536 : } else
537 0 : ifp->if_flags &= ~IFF_RUNNING;
538 :
539 : break;
540 :
541 : default:
542 0 : return (ENOTTY);
543 : }
544 0 : return (0);
545 0 : }
546 :
547 : void
548 0 : pflow_init_timeouts(struct pflow_softc *sc)
549 : {
550 0 : switch (sc->sc_version) {
551 : case PFLOW_PROTO_5:
552 0 : if (timeout_initialized(&sc->sc_tmo6))
553 0 : timeout_del(&sc->sc_tmo6);
554 0 : if (timeout_initialized(&sc->sc_tmo_tmpl))
555 0 : timeout_del(&sc->sc_tmo_tmpl);
556 0 : if (!timeout_initialized(&sc->sc_tmo))
557 0 : timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
558 : break;
559 : case PFLOW_PROTO_10:
560 0 : if (!timeout_initialized(&sc->sc_tmo_tmpl))
561 0 : timeout_set_proc(&sc->sc_tmo_tmpl, pflow_timeout_tmpl,
562 0 : sc);
563 0 : if (!timeout_initialized(&sc->sc_tmo))
564 0 : timeout_set_proc(&sc->sc_tmo, pflow_timeout, sc);
565 0 : if (!timeout_initialized(&sc->sc_tmo6))
566 0 : timeout_set_proc(&sc->sc_tmo6, pflow_timeout6, sc);
567 :
568 0 : timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
569 0 : break;
570 : default: /* NOTREACHED */
571 : break;
572 : }
573 0 : }
574 :
575 : int
576 0 : pflow_calc_mtu(struct pflow_softc *sc, int mtu, int hdrsz)
577 : {
578 :
579 0 : sc->sc_maxcount4 = (mtu - hdrsz -
580 0 : sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow4);
581 0 : sc->sc_maxcount6 = (mtu - hdrsz -
582 0 : sizeof(struct udpiphdr)) / sizeof(struct pflow_ipfix_flow6);
583 0 : if (sc->sc_maxcount4 > PFLOW_MAXFLOWS)
584 0 : sc->sc_maxcount4 = PFLOW_MAXFLOWS;
585 0 : if (sc->sc_maxcount6 > PFLOW_MAXFLOWS)
586 0 : sc->sc_maxcount6 = PFLOW_MAXFLOWS;
587 0 : return (hdrsz + sizeof(struct udpiphdr) +
588 0 : MIN(sc->sc_maxcount4 * sizeof(struct pflow_ipfix_flow4),
589 : sc->sc_maxcount6 * sizeof(struct pflow_ipfix_flow6)));
590 : }
591 :
592 : void
593 0 : pflow_setmtu(struct pflow_softc *sc, int mtu_req)
594 : {
595 : int mtu;
596 :
597 0 : if (sc->sc_pflow_ifp && sc->sc_pflow_ifp->if_mtu < mtu_req)
598 0 : mtu = sc->sc_pflow_ifp->if_mtu;
599 : else
600 : mtu = mtu_req;
601 :
602 0 : switch (sc->sc_version) {
603 : case PFLOW_PROTO_5:
604 0 : sc->sc_maxcount = (mtu - sizeof(struct pflow_header) -
605 0 : sizeof(struct udpiphdr)) / sizeof(struct pflow_flow);
606 0 : if (sc->sc_maxcount > PFLOW_MAXFLOWS)
607 0 : sc->sc_maxcount = PFLOW_MAXFLOWS;
608 0 : sc->sc_if.if_mtu = sizeof(struct pflow_header) +
609 0 : sizeof(struct udpiphdr) +
610 0 : sc->sc_maxcount * sizeof(struct pflow_flow);
611 0 : break;
612 : case PFLOW_PROTO_10:
613 0 : sc->sc_if.if_mtu =
614 0 : pflow_calc_mtu(sc, mtu, sizeof(struct pflow_v10_header));
615 0 : break;
616 : default: /* NOTREACHED */
617 : break;
618 : }
619 0 : }
620 :
621 : struct mbuf *
622 0 : pflow_get_mbuf(struct pflow_softc *sc, u_int16_t set_id)
623 : {
624 0 : struct pflow_set_header set_hdr;
625 0 : struct pflow_header h;
626 : struct mbuf *m;
627 :
628 0 : MGETHDR(m, M_DONTWAIT, MT_DATA);
629 0 : if (m == NULL) {
630 0 : pflowstats.pflow_onomem++;
631 0 : return (NULL);
632 : }
633 :
634 0 : MCLGET(m, M_DONTWAIT);
635 0 : if ((m->m_flags & M_EXT) == 0) {
636 0 : m_free(m);
637 0 : pflowstats.pflow_onomem++;
638 0 : return (NULL);
639 : }
640 :
641 0 : m->m_len = m->m_pkthdr.len = 0;
642 0 : m->m_pkthdr.ph_ifidx = 0;
643 :
644 0 : if (sc == NULL) /* get only a new empty mbuf */
645 0 : return (m);
646 :
647 0 : switch (sc->sc_version) {
648 : case PFLOW_PROTO_5:
649 : /* populate pflow_header */
650 0 : h.reserved1 = 0;
651 0 : h.reserved2 = 0;
652 0 : h.count = 0;
653 0 : h.version = htons(PFLOW_PROTO_5);
654 0 : h.flow_sequence = htonl(sc->sc_gcounter);
655 0 : h.engine_type = PFLOW_ENGINE_TYPE;
656 0 : h.engine_id = PFLOW_ENGINE_ID;
657 0 : m_copyback(m, 0, PFLOW_HDRLEN, &h, M_NOWAIT);
658 :
659 0 : sc->sc_count = 0;
660 0 : timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
661 0 : break;
662 : case PFLOW_PROTO_10:
663 : /* populate pflow_set_header */
664 0 : set_hdr.set_length = 0;
665 0 : set_hdr.set_id = htons(set_id);
666 0 : m_copyback(m, 0, PFLOW_SET_HDRLEN, &set_hdr, M_NOWAIT);
667 0 : break;
668 : default: /* NOTREACHED */
669 : break;
670 : }
671 :
672 0 : return (m);
673 0 : }
674 :
675 : void
676 0 : copy_flow_data(struct pflow_flow *flow1, struct pflow_flow *flow2,
677 : struct pf_state *st, struct pf_state_key *sk, int src, int dst)
678 : {
679 0 : flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
680 0 : flow1->src_port = flow2->dest_port = sk->port[src];
681 0 : flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
682 0 : flow1->dest_port = flow2->src_port = sk->port[dst];
683 :
684 0 : flow1->dest_as = flow2->src_as =
685 0 : flow1->src_as = flow2->dest_as = 0;
686 0 : flow1->if_index_in = htons(st->if_index_in);
687 0 : flow1->if_index_out = htons(st->if_index_out);
688 0 : flow2->if_index_in = htons(st->if_index_out);
689 0 : flow2->if_index_out = htons(st->if_index_in);
690 0 : flow1->dest_mask = flow2->src_mask =
691 0 : flow1->src_mask = flow2->dest_mask = 0;
692 :
693 0 : flow1->flow_packets = htonl(st->packets[0]);
694 0 : flow2->flow_packets = htonl(st->packets[1]);
695 0 : flow1->flow_octets = htonl(st->bytes[0]);
696 0 : flow2->flow_octets = htonl(st->bytes[1]);
697 :
698 : /*
699 : * Pretend the flow was created or expired when the machine came up
700 : * when creation is in the future of the last time a package was seen
701 : * or was created / expired before this machine came up due to pfsync.
702 : */
703 0 : flow1->flow_start = flow2->flow_start = st->creation < 0 ||
704 0 : st->creation > st->expire ? htonl(0) : htonl(st->creation * 1000);
705 0 : flow1->flow_finish = flow2->flow_finish = st->expire < 0 ? htonl(0) :
706 0 : htonl(st->expire * 1000);
707 0 : flow1->tcp_flags = flow2->tcp_flags = 0;
708 0 : flow1->protocol = flow2->protocol = sk->proto;
709 0 : flow1->tos = flow2->tos = st->rule.ptr->tos;
710 0 : }
711 :
712 : void
713 0 : copy_flow_ipfix_4_data(struct pflow_ipfix_flow4 *flow1,
714 : struct pflow_ipfix_flow4 *flow2, struct pf_state *st,
715 : struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
716 : {
717 0 : flow1->src_ip = flow2->dest_ip = sk->addr[src].v4.s_addr;
718 0 : flow1->src_port = flow2->dest_port = sk->port[src];
719 0 : flow1->dest_ip = flow2->src_ip = sk->addr[dst].v4.s_addr;
720 0 : flow1->dest_port = flow2->src_port = sk->port[dst];
721 :
722 0 : flow1->if_index_in = htonl(st->if_index_in);
723 0 : flow1->if_index_out = htonl(st->if_index_out);
724 0 : flow2->if_index_in = htonl(st->if_index_out);
725 0 : flow2->if_index_out = htonl(st->if_index_in);
726 :
727 0 : flow1->flow_packets = htobe64(st->packets[0]);
728 0 : flow2->flow_packets = htobe64(st->packets[1]);
729 0 : flow1->flow_octets = htobe64(st->bytes[0]);
730 0 : flow2->flow_octets = htobe64(st->bytes[1]);
731 :
732 : /*
733 : * Pretend the flow was created when the machine came up when creation
734 : * is in the future of the last time a package was seen due to pfsync.
735 : */
736 0 : if (st->creation > st->expire)
737 0 : flow1->flow_start = flow2->flow_start = htobe64((time_second -
738 : time_uptime)*1000);
739 : else
740 0 : flow1->flow_start = flow2->flow_start = htobe64((time_second -
741 : (time_uptime - st->creation))*1000);
742 0 : flow1->flow_finish = flow2->flow_finish = htobe64((time_second -
743 : (time_uptime - st->expire))*1000);
744 :
745 0 : flow1->protocol = flow2->protocol = sk->proto;
746 0 : flow1->tos = flow2->tos = st->rule.ptr->tos;
747 0 : }
748 :
749 : void
750 0 : copy_flow_ipfix_6_data(struct pflow_ipfix_flow6 *flow1,
751 : struct pflow_ipfix_flow6 *flow2, struct pf_state *st,
752 : struct pf_state_key *sk, struct pflow_softc *sc, int src, int dst)
753 : {
754 0 : bcopy(&sk->addr[src].v6, &flow1->src_ip, sizeof(flow1->src_ip));
755 0 : bcopy(&sk->addr[src].v6, &flow2->dest_ip, sizeof(flow2->dest_ip));
756 0 : flow1->src_port = flow2->dest_port = sk->port[src];
757 0 : bcopy(&sk->addr[dst].v6, &flow1->dest_ip, sizeof(flow1->dest_ip));
758 0 : bcopy(&sk->addr[dst].v6, &flow2->src_ip, sizeof(flow2->src_ip));
759 0 : flow1->dest_port = flow2->src_port = sk->port[dst];
760 :
761 0 : flow1->if_index_in = htonl(st->if_index_in);
762 0 : flow1->if_index_out = htonl(st->if_index_out);
763 0 : flow2->if_index_in = htonl(st->if_index_out);
764 0 : flow2->if_index_out = htonl(st->if_index_in);
765 :
766 0 : flow1->flow_packets = htobe64(st->packets[0]);
767 0 : flow2->flow_packets = htobe64(st->packets[1]);
768 0 : flow1->flow_octets = htobe64(st->bytes[0]);
769 0 : flow2->flow_octets = htobe64(st->bytes[1]);
770 :
771 : /*
772 : * Pretend the flow was created when the machine came up when creation
773 : * is in the future of the last time a package was seen due to pfsync.
774 : */
775 0 : if (st->creation > st->expire)
776 0 : flow1->flow_start = flow2->flow_start = htobe64((time_second -
777 : time_uptime)*1000);
778 : else
779 0 : flow1->flow_start = flow2->flow_start = htobe64((time_second -
780 : (time_uptime - st->creation))*1000);
781 0 : flow1->flow_finish = flow2->flow_finish = htobe64((time_second -
782 : (time_uptime - st->expire))*1000);
783 :
784 0 : flow1->protocol = flow2->protocol = sk->proto;
785 0 : flow1->tos = flow2->tos = st->rule.ptr->tos;
786 0 : }
787 :
788 : int
789 0 : export_pflow(struct pf_state *st)
790 : {
791 : struct pflow_softc *sc = NULL;
792 : struct pf_state_key *sk;
793 :
794 0 : sk = st->key[st->direction == PF_IN ? PF_SK_WIRE : PF_SK_STACK];
795 :
796 0 : SLIST_FOREACH(sc, &pflowif_list, sc_next) {
797 0 : switch (sc->sc_version) {
798 : case PFLOW_PROTO_5:
799 0 : if( sk->af == AF_INET )
800 0 : export_pflow_if(st, sk, sc);
801 : break;
802 : case PFLOW_PROTO_10:
803 0 : if( sk->af == AF_INET || sk->af == AF_INET6 )
804 0 : export_pflow_if(st, sk, sc);
805 : break;
806 : default: /* NOTREACHED */
807 : break;
808 : }
809 : }
810 :
811 0 : return (0);
812 : }
813 :
814 : int
815 0 : export_pflow_if(struct pf_state *st, struct pf_state_key *sk,
816 : struct pflow_softc *sc)
817 : {
818 0 : struct pf_state pfs_copy;
819 0 : struct ifnet *ifp = &sc->sc_if;
820 : u_int64_t bytes[2];
821 : int ret = 0;
822 :
823 0 : if (!(ifp->if_flags & IFF_RUNNING))
824 0 : return (0);
825 :
826 0 : if (sc->sc_version == PFLOW_PROTO_10)
827 0 : return (pflow_pack_flow_ipfix(st, sk, sc));
828 :
829 : /* PFLOW_PROTO_5 */
830 0 : if ((st->bytes[0] < (u_int64_t)PFLOW_MAXBYTES)
831 0 : && (st->bytes[1] < (u_int64_t)PFLOW_MAXBYTES))
832 0 : return (pflow_pack_flow(st, sk, sc));
833 :
834 : /* flow > PFLOW_MAXBYTES need special handling */
835 0 : bcopy(st, &pfs_copy, sizeof(pfs_copy));
836 0 : bytes[0] = pfs_copy.bytes[0];
837 0 : bytes[1] = pfs_copy.bytes[1];
838 :
839 0 : while (bytes[0] > PFLOW_MAXBYTES) {
840 0 : pfs_copy.bytes[0] = PFLOW_MAXBYTES;
841 0 : pfs_copy.bytes[1] = 0;
842 :
843 0 : if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0)
844 0 : return (ret);
845 0 : if ((bytes[0] - PFLOW_MAXBYTES) > 0)
846 0 : bytes[0] -= PFLOW_MAXBYTES;
847 : }
848 :
849 0 : while (bytes[1] > (u_int64_t)PFLOW_MAXBYTES) {
850 0 : pfs_copy.bytes[1] = PFLOW_MAXBYTES;
851 0 : pfs_copy.bytes[0] = 0;
852 :
853 0 : if ((ret = pflow_pack_flow(&pfs_copy, sk, sc)) != 0)
854 0 : return (ret);
855 0 : if ((bytes[1] - PFLOW_MAXBYTES) > 0)
856 0 : bytes[1] -= PFLOW_MAXBYTES;
857 : }
858 :
859 0 : pfs_copy.bytes[0] = bytes[0];
860 0 : pfs_copy.bytes[1] = bytes[1];
861 :
862 0 : return (pflow_pack_flow(&pfs_copy, sk, sc));
863 0 : }
864 :
865 : int
866 0 : copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc)
867 : {
868 : int ret = 0;
869 :
870 0 : if (sc->sc_mbuf == NULL) {
871 0 : if ((sc->sc_mbuf = pflow_get_mbuf(sc, 0)) == NULL)
872 0 : return (ENOBUFS);
873 : }
874 0 : m_copyback(sc->sc_mbuf, PFLOW_HDRLEN +
875 0 : (sc->sc_count * sizeof(struct pflow_flow)),
876 0 : sizeof(struct pflow_flow), flow, M_NOWAIT);
877 :
878 0 : if (pflowstats.pflow_flows == sc->sc_gcounter)
879 0 : pflowstats.pflow_flows++;
880 0 : sc->sc_gcounter++;
881 0 : sc->sc_count++;
882 :
883 0 : if (sc->sc_count >= sc->sc_maxcount)
884 0 : ret = pflow_sendout_v5(sc);
885 :
886 0 : return(ret);
887 0 : }
888 :
889 : int
890 0 : copy_flow_ipfix_4_to_m(struct pflow_ipfix_flow4 *flow, struct pflow_softc *sc)
891 : {
892 : int ret = 0;
893 :
894 0 : if (sc->sc_mbuf == NULL) {
895 0 : if ((sc->sc_mbuf =
896 0 : pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV4_ID)) == NULL) {
897 0 : return (ENOBUFS);
898 : }
899 0 : sc->sc_count4 = 0;
900 0 : timeout_add_sec(&sc->sc_tmo, PFLOW_TIMEOUT);
901 0 : }
902 0 : m_copyback(sc->sc_mbuf, PFLOW_SET_HDRLEN +
903 0 : (sc->sc_count4 * sizeof(struct pflow_ipfix_flow4)),
904 0 : sizeof(struct pflow_ipfix_flow4), flow, M_NOWAIT);
905 :
906 0 : if (pflowstats.pflow_flows == sc->sc_gcounter)
907 0 : pflowstats.pflow_flows++;
908 0 : sc->sc_gcounter++;
909 0 : sc->sc_count4++;
910 :
911 0 : if (sc->sc_count4 >= sc->sc_maxcount4)
912 0 : ret = pflow_sendout_ipfix(sc, AF_INET);
913 0 : return(ret);
914 0 : }
915 :
916 : int
917 0 : copy_flow_ipfix_6_to_m(struct pflow_ipfix_flow6 *flow, struct pflow_softc *sc)
918 : {
919 : int ret = 0;
920 :
921 0 : if (sc->sc_mbuf6 == NULL) {
922 0 : if ((sc->sc_mbuf6 =
923 0 : pflow_get_mbuf(sc, PFLOW_IPFIX_TMPL_IPV6_ID)) == NULL) {
924 0 : return (ENOBUFS);
925 : }
926 0 : sc->sc_count6 = 0;
927 0 : timeout_add_sec(&sc->sc_tmo6, PFLOW_TIMEOUT);
928 0 : }
929 0 : m_copyback(sc->sc_mbuf6, PFLOW_SET_HDRLEN +
930 0 : (sc->sc_count6 * sizeof(struct pflow_ipfix_flow6)),
931 0 : sizeof(struct pflow_ipfix_flow6), flow, M_NOWAIT);
932 :
933 0 : if (pflowstats.pflow_flows == sc->sc_gcounter)
934 0 : pflowstats.pflow_flows++;
935 0 : sc->sc_gcounter++;
936 0 : sc->sc_count6++;
937 :
938 0 : if (sc->sc_count6 >= sc->sc_maxcount6)
939 0 : ret = pflow_sendout_ipfix(sc, AF_INET6);
940 :
941 0 : return(ret);
942 0 : }
943 :
944 : int
945 0 : pflow_pack_flow(struct pf_state *st, struct pf_state_key *sk,
946 : struct pflow_softc *sc)
947 : {
948 0 : struct pflow_flow flow1;
949 0 : struct pflow_flow flow2;
950 : int ret = 0;
951 :
952 0 : bzero(&flow1, sizeof(flow1));
953 0 : bzero(&flow2, sizeof(flow2));
954 :
955 0 : if (st->direction == PF_OUT)
956 0 : copy_flow_data(&flow1, &flow2, st, sk, 1, 0);
957 : else
958 0 : copy_flow_data(&flow1, &flow2, st, sk, 0, 1);
959 :
960 0 : if (st->bytes[0] != 0) /* first flow from state */
961 0 : ret = copy_flow_to_m(&flow1, sc);
962 :
963 0 : if (st->bytes[1] != 0) /* second flow from state */
964 0 : ret = copy_flow_to_m(&flow2, sc);
965 :
966 0 : return (ret);
967 0 : }
968 :
969 : int
970 0 : pflow_pack_flow_ipfix(struct pf_state *st, struct pf_state_key *sk,
971 : struct pflow_softc *sc)
972 : {
973 0 : struct pflow_ipfix_flow4 flow4_1, flow4_2;
974 0 : struct pflow_ipfix_flow6 flow6_1, flow6_2;
975 : int ret = 0;
976 0 : if (sk->af == AF_INET) {
977 0 : bzero(&flow4_1, sizeof(flow4_1));
978 0 : bzero(&flow4_2, sizeof(flow4_2));
979 :
980 0 : if (st->direction == PF_OUT)
981 0 : copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
982 : 1, 0);
983 : else
984 0 : copy_flow_ipfix_4_data(&flow4_1, &flow4_2, st, sk, sc,
985 : 0, 1);
986 :
987 0 : if (st->bytes[0] != 0) /* first flow from state */
988 0 : ret = copy_flow_ipfix_4_to_m(&flow4_1, sc);
989 :
990 0 : if (st->bytes[1] != 0) /* second flow from state */
991 0 : ret = copy_flow_ipfix_4_to_m(&flow4_2, sc);
992 0 : } else if (sk->af == AF_INET6) {
993 0 : bzero(&flow6_1, sizeof(flow6_1));
994 0 : bzero(&flow6_2, sizeof(flow6_2));
995 :
996 0 : if (st->direction == PF_OUT)
997 0 : copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc,
998 : 1, 0);
999 : else
1000 0 : copy_flow_ipfix_6_data(&flow6_1, &flow6_2, st, sk, sc,
1001 : 0, 1);
1002 :
1003 0 : if (st->bytes[0] != 0) /* first flow from state */
1004 0 : ret = copy_flow_ipfix_6_to_m(&flow6_1, sc);
1005 :
1006 0 : if (st->bytes[1] != 0) /* second flow from state */
1007 0 : ret = copy_flow_ipfix_6_to_m(&flow6_2, sc);
1008 : }
1009 0 : return (ret);
1010 0 : }
1011 :
1012 : void
1013 0 : pflow_timeout(void *v)
1014 : {
1015 0 : struct pflow_softc *sc = v;
1016 :
1017 0 : switch (sc->sc_version) {
1018 : case PFLOW_PROTO_5:
1019 0 : pflow_sendout_v5(sc);
1020 0 : break;
1021 : case PFLOW_PROTO_10:
1022 0 : pflow_sendout_ipfix(sc, AF_INET);
1023 0 : break;
1024 : default: /* NOTREACHED */
1025 : break;
1026 : }
1027 0 : }
1028 :
1029 : void
1030 0 : pflow_timeout6(void *v)
1031 : {
1032 0 : struct pflow_softc *sc = v;
1033 :
1034 0 : pflow_sendout_ipfix(sc, AF_INET6);
1035 0 : }
1036 :
1037 : void
1038 0 : pflow_timeout_tmpl(void *v)
1039 : {
1040 0 : struct pflow_softc *sc = v;
1041 :
1042 0 : pflow_sendout_ipfix_tmpl(sc);
1043 0 : }
1044 :
1045 : void
1046 0 : pflow_flush(struct pflow_softc *sc)
1047 : {
1048 0 : switch (sc->sc_version) {
1049 : case PFLOW_PROTO_5:
1050 0 : pflow_sendout_v5(sc);
1051 0 : break;
1052 : case PFLOW_PROTO_10:
1053 0 : pflow_sendout_ipfix(sc, AF_INET);
1054 0 : pflow_sendout_ipfix(sc, AF_INET6);
1055 0 : break;
1056 : default: /* NOTREACHED */
1057 : break;
1058 : }
1059 0 : }
1060 :
1061 : int
1062 0 : pflow_sendout_v5(struct pflow_softc *sc)
1063 : {
1064 0 : struct mbuf *m = sc->sc_mbuf;
1065 : struct pflow_header *h;
1066 0 : struct ifnet *ifp = &sc->sc_if;
1067 0 : struct timespec tv;
1068 :
1069 0 : timeout_del(&sc->sc_tmo);
1070 :
1071 0 : if (m == NULL)
1072 0 : return (0);
1073 :
1074 0 : sc->sc_mbuf = NULL;
1075 0 : if (!(ifp->if_flags & IFF_RUNNING)) {
1076 0 : m_freem(m);
1077 0 : return (0);
1078 : }
1079 :
1080 0 : pflowstats.pflow_packets++;
1081 0 : h = mtod(m, struct pflow_header *);
1082 0 : h->count = htons(sc->sc_count);
1083 :
1084 : /* populate pflow_header */
1085 0 : h->uptime_ms = htonl(time_uptime * 1000);
1086 :
1087 0 : getnanotime(&tv);
1088 0 : h->time_sec = htonl(tv.tv_sec); /* XXX 2038 */
1089 0 : h->time_nanosec = htonl(tv.tv_nsec);
1090 0 : if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
1091 0 : task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
1092 0 : return (0);
1093 0 : }
1094 :
1095 : int
1096 0 : pflow_sendout_ipfix(struct pflow_softc *sc, sa_family_t af)
1097 : {
1098 : struct mbuf *m;
1099 : struct pflow_v10_header *h10;
1100 : struct pflow_set_header *set_hdr;
1101 0 : struct ifnet *ifp = &sc->sc_if;
1102 : u_int32_t count;
1103 : int set_length;
1104 :
1105 0 : switch (af) {
1106 : case AF_INET:
1107 0 : m = sc->sc_mbuf;
1108 0 : timeout_del(&sc->sc_tmo);
1109 0 : if (m == NULL)
1110 0 : return (0);
1111 0 : sc->sc_mbuf = NULL;
1112 0 : count = sc->sc_count4;
1113 0 : set_length = sizeof(struct pflow_set_header)
1114 0 : + sc->sc_count4 * sizeof(struct pflow_ipfix_flow4);
1115 0 : break;
1116 : case AF_INET6:
1117 0 : m = sc->sc_mbuf6;
1118 0 : timeout_del(&sc->sc_tmo6);
1119 0 : if (m == NULL)
1120 0 : return (0);
1121 0 : sc->sc_mbuf6 = NULL;
1122 0 : count = sc->sc_count6;
1123 0 : set_length = sizeof(struct pflow_set_header)
1124 0 : + sc->sc_count6 * sizeof(struct pflow_ipfix_flow6);
1125 0 : break;
1126 : default:
1127 0 : unhandled_af(af);
1128 : }
1129 :
1130 0 : if (!(ifp->if_flags & IFF_RUNNING)) {
1131 0 : m_freem(m);
1132 0 : return (0);
1133 : }
1134 :
1135 0 : pflowstats.pflow_packets++;
1136 0 : set_hdr = mtod(m, struct pflow_set_header *);
1137 0 : set_hdr->set_length = htons(set_length);
1138 :
1139 : /* populate pflow_header */
1140 0 : M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
1141 0 : if (m == NULL) {
1142 0 : pflowstats.pflow_onomem++;
1143 0 : return (ENOBUFS);
1144 : }
1145 0 : h10 = mtod(m, struct pflow_v10_header *);
1146 0 : h10->version = htons(PFLOW_PROTO_10);
1147 0 : h10->length = htons(PFLOW_IPFIX_HDRLEN + set_length);
1148 0 : h10->time_sec = htonl(time_second); /* XXX 2038 */
1149 0 : h10->flow_sequence = htonl(sc->sc_sequence);
1150 0 : sc->sc_sequence += count;
1151 0 : h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
1152 0 : if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
1153 0 : task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
1154 0 : return (0);
1155 0 : }
1156 :
1157 : int
1158 0 : pflow_sendout_ipfix_tmpl(struct pflow_softc *sc)
1159 : {
1160 : struct mbuf *m;
1161 : struct pflow_v10_header *h10;
1162 0 : struct ifnet *ifp = &sc->sc_if;
1163 :
1164 0 : timeout_del(&sc->sc_tmo_tmpl);
1165 :
1166 0 : if (!(ifp->if_flags & IFF_RUNNING)) {
1167 0 : return (0);
1168 : }
1169 0 : m = pflow_get_mbuf(NULL, 0);
1170 0 : if (m == NULL)
1171 0 : return (0);
1172 0 : if (m_copyback(m, 0, sizeof(struct pflow_ipfix_tmpl),
1173 0 : &sc->sc_tmpl_ipfix, M_NOWAIT)) {
1174 0 : m_freem(m);
1175 0 : return (0);
1176 : }
1177 0 : pflowstats.pflow_packets++;
1178 :
1179 : /* populate pflow_header */
1180 0 : M_PREPEND(m, sizeof(struct pflow_v10_header), M_DONTWAIT);
1181 0 : if (m == NULL) {
1182 0 : pflowstats.pflow_onomem++;
1183 0 : return (ENOBUFS);
1184 : }
1185 0 : h10 = mtod(m, struct pflow_v10_header *);
1186 0 : h10->version = htons(PFLOW_PROTO_10);
1187 0 : h10->length = htons(PFLOW_IPFIX_HDRLEN + sizeof(struct
1188 : pflow_ipfix_tmpl));
1189 0 : h10->time_sec = htonl(time_second); /* XXX 2038 */
1190 0 : h10->flow_sequence = htonl(sc->sc_sequence);
1191 0 : h10->observation_dom = htonl(PFLOW_ENGINE_TYPE);
1192 :
1193 0 : timeout_add_sec(&sc->sc_tmo_tmpl, PFLOW_TMPL_TIMEOUT);
1194 0 : if (mq_enqueue(&sc->sc_outputqueue, m) == 0)
1195 0 : task_add(net_tq(ifp->if_index), &sc->sc_outputtask);
1196 0 : return (0);
1197 0 : }
1198 :
1199 : int
1200 0 : pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
1201 : {
1202 0 : sc->sc_if.if_opackets++;
1203 0 : sc->sc_if.if_obytes += m->m_pkthdr.len;
1204 :
1205 0 : if (sc->so == NULL) {
1206 0 : m_freem(m);
1207 0 : return (EINVAL);
1208 : }
1209 0 : return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0));
1210 0 : }
1211 :
1212 : int
1213 0 : pflow_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
1214 : void *newp, size_t newlen)
1215 : {
1216 0 : if (namelen != 1)
1217 0 : return (ENOTDIR);
1218 :
1219 0 : switch (name[0]) {
1220 : case NET_PFLOW_STATS:
1221 0 : if (newp != NULL)
1222 0 : return (EPERM);
1223 0 : return (sysctl_struct(oldp, oldlenp, newp, newlen,
1224 : &pflowstats, sizeof(pflowstats)));
1225 : default:
1226 0 : return (EOPNOTSUPP);
1227 : }
1228 : return (0);
1229 0 : }
|