summaryrefslogtreecommitdiffstats
path: root/sys/netinet/ip_divert.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netinet/ip_divert.c')
-rw-r--r--sys/netinet/ip_divert.c69
1 files changed, 48 insertions, 21 deletions
diff --git a/sys/netinet/ip_divert.c b/sys/netinet/ip_divert.c
index fe560a0..ee1f97c 100644
--- a/sys/netinet/ip_divert.c
+++ b/sys/netinet/ip_divert.c
@@ -68,6 +68,7 @@
#include <netinet/in_systm.h>
#include <netinet/in_var.h>
#include <netinet/ip.h>
+#include <netinet/ip_divert.h>
#include <netinet/ip_var.h>
/*
@@ -150,17 +151,21 @@ div_input(struct mbuf *m, int off)
* then pass them along with mbuf chain.
*/
void
-divert_packet(struct mbuf *m, int incoming, int port, int rule)
+divert_packet(struct mbuf *m, int incoming)
{
struct ip *ip;
struct inpcb *inp;
struct socket *sa;
u_int16_t nport;
struct sockaddr_in divsrc;
+ struct m_tag *mtag;
- /* Sanity check */
- KASSERT(port != 0, ("%s: port=0", __func__));
-
+ mtag = m_tag_find(m, PACKET_TAG_DIVERT, NULL);
+ if (mtag == NULL) {
+ printf("%s: no divert tag\n", __func__);
+ m_freem(m);
+ return;
+ }
/* Assure header */
if (m->m_len < sizeof(struct ip) &&
(m = m_pullup(m, sizeof(struct ip))) == 0)
@@ -174,7 +179,7 @@ divert_packet(struct mbuf *m, int incoming, int port, int rule)
bzero(&divsrc, sizeof(divsrc));
divsrc.sin_len = sizeof(divsrc);
divsrc.sin_family = AF_INET;
- divsrc.sin_port = rule; /* record matching rule */
+ divsrc.sin_port = divert_cookie(mtag); /* record matching rule */
if (incoming) {
struct ifaddr *ifa;
@@ -234,7 +239,7 @@ divert_packet(struct mbuf *m, int incoming, int port, int rule)
mtx_lock(&Giant);
/* Put packet on socket queue, if any */
sa = NULL;
- nport = htons((u_int16_t)port);
+ nport = htons((u_int16_t)divert_info(mtag));
INP_INFO_RLOCK(&divcbinfo);
LIST_FOREACH(inp, &divcb, inp_list) {
INP_LOCK(inp);
@@ -273,19 +278,8 @@ div_output(struct socket *so, struct mbuf *m,
struct sockaddr_in *sin, struct mbuf *control)
{
int error = 0;
- struct m_hdr divert_tag;
- /*
- * Prepare the tag for divert info. Note that a packet
- * with a 0 tag in mh_data is effectively untagged,
- * so we could optimize that case.
- */
- divert_tag.mh_type = MT_TAG;
- divert_tag.mh_flags = PACKET_TAG_DIVERT;
- divert_tag.mh_next = m;
- divert_tag.mh_data = 0; /* the matching rule # */
- divert_tag.mh_nextpkt = NULL;
- m->m_pkthdr.rcvif = NULL; /* XXX is it necessary ? */
+ KASSERT(m->m_pkthdr.rcvif == NULL, ("rcvif not null"));
#ifdef MAC
mac_create_mbuf_from_socket(so, m);
@@ -296,9 +290,21 @@ div_output(struct socket *so, struct mbuf *m,
/* Loopback avoidance and state recovery */
if (sin) {
+ struct m_tag *mtag;
+ struct divert_tag *dt;
int i;
- divert_tag.mh_data = (caddr_t)(uintptr_t)sin->sin_port;
+ mtag = m_tag_get(PACKET_TAG_DIVERT,
+ sizeof(struct divert_tag), M_NOWAIT);
+ if (mtag == NULL) {
+ error = ENOBUFS;
+ goto cantsend;
+ }
+ dt = (struct divert_tag *)(mtag+1);
+ dt->info = 0;
+ dt->cookie = sin->sin_port;
+ m_tag_prepend(m, mtag);
+
/*
* Find receive interface with the given name, stuffed
* (if it exists) in the sin_zero[] field.
@@ -335,7 +341,7 @@ div_output(struct socket *so, struct mbuf *m,
/* Send packet to output processing */
ipstat.ips_rawout++; /* XXX */
- error = ip_output((struct mbuf *)&divert_tag,
+ error = ip_output(m,
inp->inp_options, NULL,
(so->so_options & SO_DONTROUTE) |
IP_ALLOWBROADCAST | IP_RAWOUTPUT,
@@ -362,7 +368,7 @@ div_output(struct socket *so, struct mbuf *m,
m->m_pkthdr.rcvif = ifa->ifa_ifp;
}
/* Send packet to input processing */
- ip_input((struct mbuf *)&divert_tag);
+ ip_input(m);
}
return error;
@@ -372,6 +378,27 @@ cantsend:
return error;
}
+/*
+ * Return a copy of the specified packet, but without
+ * the divert tag. This is used when packets are ``tee'd''
+ * and we want the cloned copy to not have divert processing.
+ */
+struct mbuf *
+divert_clone(struct mbuf *m)
+{
+ struct mbuf *clone;
+ struct m_tag *mtag;
+
+ clone = m_dup(m, M_DONTWAIT);
+ if (clone != NULL) {
+ /* strip divert tag from copy */
+ mtag = m_tag_find(clone, PACKET_TAG_DIVERT, NULL);
+ if (mtag != NULL)
+ m_tag_delete(clone, mtag);
+ }
+ return clone;
+}
+
static int
div_attach(struct socket *so, int proto, struct thread *td)
{
OpenPOWER on IntegriCloud