Changeset View
Standalone View
sys/netpfil/pf/if_pfsync.c
Context not available. | |||||
#include <sys/mbuf.h> | #include <sys/mbuf.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/mutex.h> | #include <sys/mutex.h> | ||||
#include <sys/nv.h> | |||||
#include <sys/priv.h> | #include <sys/priv.h> | ||||
#include <sys/smp.h> | #include <sys/smp.h> | ||||
#include <sys/socket.h> | #include <sys/socket.h> | ||||
glebius: What did bring in this requirement? | |||||
Done Inline Actions
email_luiz.eng.br: > What did bring in this requirement?
| |||||
Not Done Inline ActionsIt doesn't belong on this diff, ended up here by accident. With the IPv6 code in place, it's needed in order to have RT_DEFAULT_FIB for a in6_selectsrc_addr() call. email_luiz.eng.br: It doesn't belong on this diff, ended up here by accident.
With the IPv6 code in place, it's… | |||||
Context not available. | |||||
#include <netinet/tcp_fsm.h> | #include <netinet/tcp_fsm.h> | ||||
#include <netinet/tcp_seq.h> | #include <netinet/tcp_seq.h> | ||||
#include <netpfil/pf/pfsync_nv.h> | |||||
struct pfsync_bucket; | |||||
union inet_template { | |||||
struct ip ipv4; | |||||
}; | |||||
#define PFSYNC_MINPKT ( \ | #define PFSYNC_MINPKT ( \ | ||||
sizeof(struct ip) + \ | sizeof(union inet_template) + \ | ||||
sizeof(struct pfsync_header) + \ | sizeof(struct pfsync_header) + \ | ||||
sizeof(struct pfsync_subheader) ) | sizeof(struct pfsync_subheader) ) | ||||
struct pfsync_bucket; | |||||
static int pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *, | static int pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *, | ||||
Not Done Inline ActionsSame question here. If we change the size of pfsync_pkt we're going to be changing the on-wire protocol, and that's going to break sync between versions with and without IPv6 support. kp: Same question here. If we change the size of pfsync_pkt we're going to be changing the on-wire… | |||||
Not Done Inline ActionsSame as the previous case, I did the change without being aware of the implications. I honestly don't have an idea on how to deal with it. I welcome any suggestions. email_luiz.eng.br: Same as the previous case, I did the change without being aware of the implications.
I… | |||||
struct pfsync_state_peer *); | struct pfsync_state_peer *); | ||||
static int pfsync_in_clr(struct mbuf *, int, int, int); | static int pfsync_in_clr(struct mbuf *, int, int, int); | ||||
Context not available. | |||||
struct ifnet *sc_ifp; | struct ifnet *sc_ifp; | ||||
struct ifnet *sc_sync_if; | struct ifnet *sc_sync_if; | ||||
struct ip_moptions sc_imo; | struct ip_moptions sc_imo; | ||||
struct in_addr sc_sync_peer; | struct sockaddr_storage sc_sync_peer; | ||||
uint32_t sc_flags; | uint32_t sc_flags; | ||||
uint8_t sc_maxupdates; | uint8_t sc_maxupdates; | ||||
struct ip sc_template; | union inet_template sc_template; | ||||
struct mtx sc_mtx; | struct mtx sc_mtx; | ||||
/* Queued data */ | /* Queued data */ | ||||
Context not available. | |||||
return (error); | return (error); | ||||
} | } | ||||
#ifdef INET | |||||
static int | static int | ||||
pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused) | pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused) | ||||
{ | { | ||||
Context not available. | |||||
m_freem(m); | m_freem(m); | ||||
return (IPPROTO_DONE); | return (IPPROTO_DONE); | ||||
} | } | ||||
#endif | |||||
static int | static int | ||||
pfsync_in_clr(struct mbuf *m, int offset, int count, int flags) | pfsync_in_clr(struct mbuf *m, int offset, int count, int flags) | ||||
Context not available. | |||||
struct pfsync_softc *sc = ifp->if_softc; | struct pfsync_softc *sc = ifp->if_softc; | ||||
struct ifreq *ifr = (struct ifreq *)data; | struct ifreq *ifr = (struct ifreq *)data; | ||||
struct pfsyncreq pfsyncr; | struct pfsyncreq pfsyncr; | ||||
size_t nvbuflen; | |||||
int error; | int error; | ||||
int c; | int c; | ||||
Context not available. | |||||
ifp->if_mtu = ifr->ifr_mtu; | ifp->if_mtu = ifr->ifr_mtu; | ||||
break; | break; | ||||
case SIOCGETPFSYNC: | case SIOCGETPFSYNC: | ||||
// XXX: Already changed to match the new softc struct | |||||
bzero(&pfsyncr, sizeof(pfsyncr)); | bzero(&pfsyncr, sizeof(pfsyncr)); | ||||
PFSYNC_LOCK(sc); | PFSYNC_LOCK(sc); | ||||
if (sc->sc_sync_if) { | if (sc->sc_sync_if) { | ||||
strlcpy(pfsyncr.pfsyncr_syncdev, | strlcpy(pfsyncr.pfsyncr_syncdev, | ||||
sc->sc_sync_if->if_xname, IFNAMSIZ); | sc->sc_sync_if->if_xname, IFNAMSIZ); | ||||
} | } | ||||
Done Inline ActionsIs this comment still relevant? kp: Is this comment still relevant? | |||||
pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer; | pfsyncr.pfsyncr_syncpeer = ((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr; | ||||
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; | pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates; | ||||
pfsyncr.pfsyncr_defer = sc->sc_flags; | pfsyncr.pfsyncr_defer = sc->sc_flags; | ||||
PFSYNC_UNLOCK(sc); | PFSYNC_UNLOCK(sc); | ||||
return (copyout(&pfsyncr, ifr_data_get_ptr(ifr), | return (copyout(&pfsyncr, ifr_data_get_ptr(ifr), | ||||
sizeof(pfsyncr))); | sizeof(pfsyncr))); | ||||
case SIOCGETPFSYNCNV: | |||||
{ | |||||
nvlist_t *nvl_syncpeer; | |||||
nvlist_t *nvl = nvlist_create(0); | |||||
if (nvl == NULL) | |||||
return (ENOMEM); | |||||
if (sc->sc_sync_if) | |||||
nvlist_add_string(nvl, "syncdev", sc->sc_sync_if->if_xname); | |||||
nvlist_add_number(nvl, "maxupdates", sc->sc_maxupdates); | |||||
nvlist_add_number(nvl, "flags", sc->sc_flags); | |||||
if ((nvl_syncpeer = pfsync_sockaddr_to_syncpeer_nvlist(&sc->sc_sync_peer)) != NULL) | |||||
nvlist_add_nvlist(nvl, "syncpeer", nvl_syncpeer); | |||||
void *packed = NULL; | |||||
packed = nvlist_pack(nvl, &nvbuflen); | |||||
if (packed == NULL) { | |||||
error = nvlist_error(nvl); | |||||
if (error == 0) | |||||
error = EDOOFUS; | |||||
free(packed, M_NVLIST); | |||||
nvlist_destroy(nvl); | |||||
return error; | |||||
} | |||||
Done Inline ActionsI'd just ENOMEM here, that's by far the most likely cause anyway, and nvlist_error() isn't going to tell us that. kp: I'd just ENOMEM here, that's by far the most likely cause anyway, and nvlist_error() isn't… | |||||
if (nvbuflen > ifr->ifr_cap_nv.buf_length) { | |||||
ifr->ifr_cap_nv.length = nvbuflen; | |||||
Done Inline ActionsWe're leaking packed and nvl here. kp: We're leaking packed and nvl here. | |||||
ifr->ifr_cap_nv.buffer = NULL; | |||||
free(packed, M_NVLIST); | |||||
nvlist_destroy(nvl); | |||||
return (EFBIG); | |||||
} | |||||
ifr->ifr_cap_nv.length = nvbuflen; | |||||
error = copyout(packed, ifr->ifr_cap_nv.buffer, nvbuflen); | |||||
nvlist_destroy(nvl); | |||||
nvlist_destroy(nvl_syncpeer); | |||||
free(packed, M_NVLIST); | |||||
break; | |||||
} | |||||
case SIOCSETPFSYNC: | case SIOCSETPFSYNC: | ||||
{ | { | ||||
struct in_mfilter *imf = NULL; | struct in_mfilter *imf = NULL; | ||||
Context not available. | |||||
imf = ip_mfilter_alloc(M_WAITOK, 0, 0); | imf = ip_mfilter_alloc(M_WAITOK, 0, 0); | ||||
PFSYNC_LOCK(sc); | PFSYNC_LOCK(sc); | ||||
if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) | struct sockaddr_in *sin = | ||||
sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP); | (struct sockaddr_in *)&sc->sc_sync_peer; | ||||
else | sin->sin_family = AF_INET; | ||||
sc->sc_sync_peer.s_addr = | sin->sin_len = sizeof(*sin); | ||||
pfsyncr.pfsyncr_syncpeer.s_addr; | if (pfsyncr.pfsyncr_syncpeer.s_addr == 0) { | ||||
sin->sin_addr.s_addr = htonl(INADDR_PFSYNC_GROUP); | |||||
} else { | |||||
sin->sin_addr.s_addr = pfsyncr.pfsyncr_syncpeer.s_addr; | |||||
} | |||||
sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; | sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; | ||||
if (pfsyncr.pfsyncr_defer & PFSYNCF_DEFER) { | if (pfsyncr.pfsyncr_defer & PFSYNCF_DEFER) { | ||||
Context not available. | |||||
pfsync_multicast_cleanup(sc); | pfsync_multicast_cleanup(sc); | ||||
if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { | if (sin->sin_addr.s_addr == htonl(INADDR_PFSYNC_GROUP)) { | ||||
error = pfsync_multicast_setup(sc, sifp, imf); | error = pfsync_multicast_setup(sc, sifp, imf); | ||||
if (error) { | if (error) { | ||||
if_rele(sifp); | if_rele(sifp); | ||||
Context not available. | |||||
if_rele(sc->sc_sync_if); | if_rele(sc->sc_sync_if); | ||||
sc->sc_sync_if = sifp; | sc->sc_sync_if = sifp; | ||||
ip = &sc->sc_template; | ip = &sc->sc_template.ipv4; | ||||
bzero(ip, sizeof(*ip)); | bzero(ip, sizeof(*ip)); | ||||
ip->ip_v = IPVERSION; | ip->ip_v = IPVERSION; | ||||
ip->ip_hl = sizeof(sc->sc_template) >> 2; | ip->ip_hl = sizeof(sc->sc_template.ipv4) >> 2; | ||||
ip->ip_tos = IPTOS_LOWDELAY; | ip->ip_tos = IPTOS_LOWDELAY; | ||||
/* len and id are set later. */ | /* len and id are set later. */ | ||||
ip->ip_off = htons(IP_DF); | ip->ip_off = htons(IP_DF); | ||||
ip->ip_ttl = PFSYNC_DFLTTL; | ip->ip_ttl = PFSYNC_DFLTTL; | ||||
ip->ip_p = IPPROTO_PFSYNC; | ip->ip_p = IPPROTO_PFSYNC; | ||||
ip->ip_src.s_addr = INADDR_ANY; | ip->ip_src.s_addr = INADDR_ANY; | ||||
ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr; | ip->ip_dst.s_addr = sin->sin_addr.s_addr; | ||||
/* Request a full state table update. */ | /* Request a full state table update. */ | ||||
if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) | if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) | ||||
Context not available. | |||||
sc); | sc); | ||||
PFSYNC_BUNLOCK(sc); | PFSYNC_BUNLOCK(sc); | ||||
break; | |||||
} | |||||
case SIOCSETPFSYNCNV: | |||||
Not Done Inline ActionsWe should probably separate the input parsing (struct vs nvlist) from the actual pfsync configuration so we can re-use the latter for both cases. kp: We should probably separate the input parsing (struct vs nvlist) from the actual pfsync… | |||||
{ | |||||
struct pfsync_kstatus status; | |||||
struct in_mfilter *imf = NULL; | |||||
struct ifnet *sifp; | |||||
struct ip *ip; | |||||
void *data; | |||||
nvlist_t *nvl; | |||||
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) | |||||
return (error); | |||||
if (ifr->ifr_cap_nv.length > IFR_CAP_NV_MAXBUFSIZE) | |||||
return (EINVAL); | |||||
memset((char *)&status, 0, sizeof(struct pfsync_kstatus)); | |||||
data = malloc(ifr->ifr_cap_nv.length, M_TEMP, M_WAITOK); | |||||
if ((error = copyin(ifr->ifr_cap_nv.buffer, data, | |||||
ifr->ifr_cap_nv.length)) != 0) { | |||||
free(data, M_TEMP); | |||||
Not Done Inline ActionsWe'd leak data here. Unless we failed to allocate data, in which case I'm not sure what copyin() will do. kp: We'd leak data here. Unless we failed to allocate data, in which case I'm not sure what copyin… | |||||
Not Done Inline ActionsI am freeing data before returning now. According to copy(9), "All but copystr() return EFAULT if a bad address is encountered". So if the allocation fails, copyin() will see the address NULL and return EFAULT, right? email_luiz.eng.br: I am freeing data before returning now.
According to `copy(9)`, "All but copystr() return… | |||||
return (error); | |||||
} | |||||
if ((nvl = nvlist_unpack(data, ifr->ifr_cap_nv.length, 0)) == NULL) { | |||||
free(data, M_TEMP); | |||||
return (EINVAL); | |||||
} | |||||
Done Inline ActionsHow so? It should be safe as soon as you've copied the strings out. (numbers are always copied, as are bools. Byte arrays and strings need to be copied, but always should be, because we can't reasonably rely on the lifetime of the nvlist structure). kp: How so? It should be safe as soon as you've copied the strings out. (numbers are always copied… | |||||
Done Inline ActionsI wrote that when I still had a very poor understanding of nvlists. I removed the comment. email_luiz.eng.br: I wrote that when I still had a very poor understanding of nvlists. I removed the comment. | |||||
pfsync_nvstatus_to_kstatus(nvl, &status); | |||||
nvlist_destroy(nvl); | |||||
Not Done Inline ActionsLeaks data. kp: Leaks data. | |||||
Not Done Inline ActionsI went with freeing data right after the nvlist_destroy(), which covers this case and prevents leaking on normal execution as well. email_luiz.eng.br: I went with freeing data right after the nvlist_destroy(), which covers this case and prevents… | |||||
free(data, M_TEMP); | |||||
if ((status.maxupdates < 0) || (status.maxupdates > 255)) | |||||
return (EINVAL); | |||||
if (status.syncdev[0] == '\0') | |||||
sifp = NULL; | |||||
else if ((sifp = ifunit_ref(status.syncdev)) == NULL) | |||||
return (EINVAL); | |||||
struct sockaddr_in *status_sin = | |||||
(struct sockaddr_in *)&(status.syncpeer); | |||||
if (sifp != NULL && (status_sin->sin_addr.s_addr == 0 || | |||||
status_sin->sin_addr.s_addr == | |||||
htonl(INADDR_PFSYNC_GROUP))) | |||||
imf = ip_mfilter_alloc(M_WAITOK, 0, 0); | |||||
PFSYNC_LOCK(sc); | |||||
struct sockaddr_in *sc_sin = (struct sockaddr_in *)&sc->sc_sync_peer; | |||||
sc_sin->sin_family = AF_INET; | |||||
sc_sin->sin_len = sizeof(*sc_sin); | |||||
if (status_sin->sin_addr.s_addr == 0) { | |||||
sc_sin->sin_addr.s_addr = htonl(INADDR_PFSYNC_GROUP); | |||||
} else { | |||||
sc_sin->sin_addr.s_addr = status_sin->sin_addr.s_addr; | |||||
} | |||||
sc->sc_maxupdates = status.maxupdates; | |||||
if (status.flags & PFSYNCF_DEFER) { | |||||
sc->sc_flags |= PFSYNCF_DEFER; | |||||
V_pfsync_defer_ptr = pfsync_defer; | |||||
} else { | |||||
sc->sc_flags &= ~PFSYNCF_DEFER; | |||||
V_pfsync_defer_ptr = NULL; | |||||
} | |||||
if (sifp == NULL) { | |||||
if (sc->sc_sync_if) | |||||
if_rele(sc->sc_sync_if); | |||||
sc->sc_sync_if = NULL; | |||||
pfsync_multicast_cleanup(sc); | |||||
PFSYNC_UNLOCK(sc); | |||||
break; | |||||
} | |||||
for (c = 0; c < pfsync_buckets; c++) { | |||||
PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]); | |||||
if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT && | |||||
(sifp->if_mtu < sc->sc_ifp->if_mtu || | |||||
(sc->sc_sync_if != NULL && | |||||
sifp->if_mtu < sc->sc_sync_if->if_mtu) || | |||||
sifp->if_mtu < MCLBYTES - sizeof(struct ip))) | |||||
pfsync_sendout(1, c); | |||||
PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]); | |||||
} | |||||
pfsync_multicast_cleanup(sc); | |||||
if (sc_sin->sin_addr.s_addr == htonl(INADDR_PFSYNC_GROUP)) { | |||||
error = pfsync_multicast_setup(sc, sifp, imf); | |||||
if (error) { | |||||
if_rele(sifp); | |||||
ip_mfilter_free(imf); | |||||
PFSYNC_UNLOCK(sc); | |||||
return (error); | |||||
} | |||||
} | |||||
if (sc->sc_sync_if) | |||||
if_rele(sc->sc_sync_if); | |||||
sc->sc_sync_if = sifp; | |||||
ip = &sc->sc_template.ipv4; | |||||
bzero(ip, sizeof(*ip)); | |||||
ip->ip_v = IPVERSION; | |||||
ip->ip_hl = sizeof(sc->sc_template.ipv4) >> 2; | |||||
ip->ip_tos = IPTOS_LOWDELAY; | |||||
/* len and id are set later. */ | |||||
ip->ip_off = htons(IP_DF); | |||||
ip->ip_ttl = PFSYNC_DFLTTL; | |||||
ip->ip_p = IPPROTO_PFSYNC; | |||||
ip->ip_src.s_addr = INADDR_ANY; | |||||
ip->ip_dst.s_addr = sc_sin->sin_addr.s_addr; | |||||
/* Request a full state table update. */ | |||||
if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) | |||||
(*carp_demote_adj_p)(V_pfsync_carp_adj, | |||||
"pfsync bulk start"); | |||||
sc->sc_flags &= ~PFSYNCF_OK; | |||||
if (V_pf_status.debug >= PF_DEBUG_MISC) | |||||
printf("pfsync: requesting bulk update\n"); | |||||
PFSYNC_UNLOCK(sc); | |||||
PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]); | |||||
pfsync_request_update(0, 0); | |||||
PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]); | |||||
PFSYNC_BLOCK(sc); | |||||
sc->sc_ureq_sent = time_uptime; | |||||
callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, | |||||
sc); | |||||
PFSYNC_BUNLOCK(sc); | |||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
Context not available. | |||||
struct pfsync_softc *sc = V_pfsyncif; | struct pfsync_softc *sc = V_pfsyncif; | ||||
struct ifnet *ifp = sc->sc_ifp; | struct ifnet *ifp = sc->sc_ifp; | ||||
struct mbuf *m; | struct mbuf *m; | ||||
struct ip *ip; | |||||
struct pfsync_header *ph; | struct pfsync_header *ph; | ||||
struct pfsync_subheader *subh; | struct pfsync_subheader *subh; | ||||
struct pf_kstate *st, *st_next; | struct pf_kstate *st, *st_next; | ||||
struct pfsync_upd_req_item *ur; | struct pfsync_upd_req_item *ur; | ||||
struct pfsync_bucket *b = &sc->sc_buckets[c]; | struct pfsync_bucket *b = &sc->sc_buckets[c]; | ||||
int offset; | int aflen, offset; | ||||
int q, count = 0; | int q, count = 0; | ||||
KASSERT(sc != NULL, ("%s: null sc", __func__)); | KASSERT(sc != NULL, ("%s: null sc", __func__)); | ||||
Context not available. | |||||
m->m_len = m->m_pkthdr.len = b->b_len; | m->m_len = m->m_pkthdr.len = b->b_len; | ||||
/* build the ip header */ | /* build the ip header */ | ||||
ip = (struct ip *)m->m_data; | switch (sc->sc_sync_peer.ss_family) { | ||||
bcopy(&sc->sc_template, ip, sizeof(*ip)); | #ifdef INET | ||||
offset = sizeof(*ip); | case AF_INET: | ||||
{ | |||||
struct ip *ip; | |||||
ip = mtod(m, struct ip *); | |||||
bcopy(&sc->sc_template.ipv4, ip, sizeof(*ip)); | |||||
aflen = offset = sizeof(*ip); | |||||
ip->ip_len = htons(m->m_pkthdr.len); | |||||
ip_fillid(ip); | |||||
break; | |||||
} | |||||
#endif | |||||
default: | |||||
return; | |||||
} | |||||
ip->ip_len = htons(m->m_pkthdr.len); | |||||
ip_fillid(ip); | |||||
/* build the pfsync header */ | /* build the pfsync header */ | ||||
ph = (struct pfsync_header *)(m->m_data + offset); | ph = (struct pfsync_header *)(m->m_data + offset); | ||||
Context not available. | |||||
offset += sizeof(*ph); | offset += sizeof(*ph); | ||||
ph->version = PFSYNC_VERSION; | ph->version = PFSYNC_VERSION; | ||||
ph->len = htons(b->b_len - sizeof(*ip)); | ph->len = htons(b->b_len - aflen); | ||||
bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); | bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH); | ||||
/* walk the queues */ | /* walk the queues */ | ||||
Context not available. | |||||
/* we're done, let's put it on the wire */ | /* we're done, let's put it on the wire */ | ||||
if (ifp->if_bpf) { | if (ifp->if_bpf) { | ||||
m->m_data += sizeof(*ip); | m->m_data += aflen; | ||||
m->m_len = m->m_pkthdr.len = b->b_len - sizeof(*ip); | m->m_len = m->m_pkthdr.len = b->b_len - aflen; | ||||
BPF_MTAP(ifp, m); | BPF_MTAP(ifp, m); | ||||
m->m_data -= sizeof(*ip); | m->m_data -= aflen; | ||||
m->m_len = m->m_pkthdr.len = b->b_len; | m->m_len = m->m_pkthdr.len = b->b_len; | ||||
} | } | ||||
Context not available. | |||||
free(pd, M_PFSYNC); | free(pd, M_PFSYNC); | ||||
PFSYNC_BUCKET_UNLOCK(b); | PFSYNC_BUCKET_UNLOCK(b); | ||||
ip_output(m, NULL, NULL, 0, NULL, NULL); | switch (sc->sc_sync_peer.ss_family) { | ||||
#ifdef INET | |||||
case AF_INET: | |||||
ip_output(m, NULL, NULL, 0, NULL, NULL); | |||||
break; | |||||
#endif | |||||
} | |||||
pf_release_state(st); | pf_release_state(st); | ||||
Context not available. | |||||
struct pfsync_softc *sc = arg; | struct pfsync_softc *sc = arg; | ||||
struct pfsync_bucket *b; | struct pfsync_bucket *b; | ||||
struct mbuf *m, *n; | struct mbuf *m, *n; | ||||
int c; | int c, error; | ||||
NET_EPOCH_ENTER(et); | NET_EPOCH_ENTER(et); | ||||
CURVNET_SET(sc->sc_ifp->if_vnet); | CURVNET_SET(sc->sc_ifp->if_vnet); | ||||
Context not available. | |||||
* own pfsync packet based on M_SKIP_FIREWALL | * own pfsync packet based on M_SKIP_FIREWALL | ||||
* flag. This is XXX. | * flag. This is XXX. | ||||
*/ | */ | ||||
if (m->m_flags & M_SKIP_FIREWALL) | switch (sc->sc_sync_peer.ss_family) { | ||||
ip_output(m, NULL, NULL, 0, NULL, NULL); | #ifdef INET | ||||
else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, | case AF_INET: | ||||
NULL) == 0) | if (m->m_flags & M_SKIP_FIREWALL) { | ||||
error = ip_output(m, NULL, NULL, 0, | |||||
NULL, NULL); | |||||
} else { | |||||
error = ip_output(m, NULL, NULL, | |||||
IP_RAWOUTPUT, &sc->sc_imo, NULL); | |||||
} | |||||
break; | |||||
#endif | |||||
} | |||||
if (error == 0) | |||||
V_pfsyncstats.pfsyncs_opackets++; | V_pfsyncstats.pfsyncs_opackets++; | ||||
else | else | ||||
V_pfsyncstats.pfsyncs_oerrors++; | V_pfsyncstats.pfsyncs_oerrors++; | ||||
Context not available. | |||||
if (!(ifp->if_flags & IFF_MULTICAST)) | if (!(ifp->if_flags & IFF_MULTICAST)) | ||||
return (EADDRNOTAVAIL); | return (EADDRNOTAVAIL); | ||||
imo->imo_multicast_vif = -1; | switch (sc->sc_sync_peer.ss_family) { | ||||
#ifdef INET | |||||
if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL, | case AF_INET: | ||||
&imf->imf_inm)) != 0) | { | ||||
return (error); | ip_mfilter_init(&imo->imo_head); | ||||
imo->imo_multicast_vif = -1; | |||||
if ((error = in_joingroup(ifp, &((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr, NULL, | |||||
&imf->imf_inm)) != 0) | |||||
return (error); | |||||
ip_mfilter_init(&imo->imo_head); | ip_mfilter_insert(&imo->imo_head, imf); | ||||
ip_mfilter_insert(&imo->imo_head, imf); | imo->imo_multicast_ifp = ifp; | ||||
imo->imo_multicast_ifp = ifp; | imo->imo_multicast_ttl = PFSYNC_DFLTTL; | ||||
imo->imo_multicast_ttl = PFSYNC_DFLTTL; | imo->imo_multicast_loop = 0; | ||||
imo->imo_multicast_loop = 0; | break; | ||||
} | |||||
#endif | |||||
} | |||||
return (0); | return (0); | ||||
} | } | ||||
Context not available. |
What did bring in this requirement?