mirror of
https://github.com/haproxy/haproxy.git
synced 2026-02-03 20:39:41 -05:00
MINOR: net_helper: add sample converters to decode ethernet frames
This adds a few converters that help decode parts of ethernet frame headers: - eth.data : returns the next header (typically IP) - eth.dst : returns the destination MAC address - eth.hdr : returns only the ethernet header - eth.proto: returns the ethernet proto - eth.src : returns the source MAC address - eth.vlan : returns the VLAN ID when present These can be used with the tcp-ss bind option. The doc was updated accordingly.
This commit is contained in:
parent
933cb76461
commit
90d2f157f2
3 changed files with 191 additions and 7 deletions
2
Makefile
2
Makefile
|
|
@ -992,7 +992,7 @@ OBJS += src/mux_h2.o src/mux_h1.o src/mux_fcgi.o src/log.o \
|
|||
src/cfgcond.o src/proto_udp.o src/lb_fwlc.o src/ebmbtree.o \
|
||||
src/proto_uxdg.o src/cfgdiag.o src/sock_unix.o src/sha1.o \
|
||||
src/lb_fas.o src/clock.o src/sock_inet.o src/ev_select.o \
|
||||
src/lb_map.o src/shctx.o src/hpack-dec.o \
|
||||
src/lb_map.o src/shctx.o src/hpack-dec.o src/net_helper.o \
|
||||
src/arg.o src/signal.o src/fix.o src/dynbuf.o src/guid.o \
|
||||
src/cfgparse-tcp.o src/lb_ss.o src/chunk.o src/counters.o \
|
||||
src/cfgparse-unix.o src/regex.o src/fcgi.o src/uri_auth.o \
|
||||
|
|
|
|||
|
|
@ -20471,6 +20471,12 @@ debug([prefix][,destination]) any same
|
|||
digest(algorithm) binary binary
|
||||
div(value) integer integer
|
||||
djb2([avalanche]) binary integer
|
||||
eth.data binary binary
|
||||
eth.dst binary binary
|
||||
eth.hdr binary binary
|
||||
eth.proto binary integer
|
||||
eth.src binary binary
|
||||
eth.vlan binary integer
|
||||
even integer boolean
|
||||
field(index,delimiters[,count]) string string
|
||||
fix_is_valid binary boolean
|
||||
|
|
@ -20890,6 +20896,48 @@ djb2([<avalanche>])
|
|||
32-bit hash is trivial to break. See also "crc32", "sdbm", "wt6", "crc32c",
|
||||
and the "hash-type" directive.
|
||||
|
||||
eth.data
|
||||
This is used with an input sample representing a binary Ethernet frame, as
|
||||
returned by "fc_saved_syn" combined with the "tcp-ss" bind option set to "2".
|
||||
It skips all the Ethernet header including possible VLANs and returns a block
|
||||
of binary data starting at the layer 3 protocol (usually IPv4 or IPv6). See
|
||||
also "fc_saved_syn" and "tcp-ss".
|
||||
|
||||
eth.dst
|
||||
This is used with an input sample representing a binary Ethernet frame, as
|
||||
returned by "fc_saved_syn" combined with the "tcp-ss" bind option set to "2".
|
||||
It returns the 6 bytes of the Ethernet header corresponding to the
|
||||
destination address of the frame, as a binary block. See also "fc_saved_syn"
|
||||
and "tcp-ss".
|
||||
|
||||
eth.hdr
|
||||
This is used with an input sample representing a binary Ethernet frame, as
|
||||
returned by "fc_saved_syn" combined with the "tcp-ss" bind option set to "2".
|
||||
It trims anything past the Ethernet header but keeps possible VLANs, and
|
||||
returns this header as a block of binary data. See also "fc_saved_syn" and
|
||||
"tcp-ss".
|
||||
|
||||
eth.proto
|
||||
This is used with an input sample representing a binary Ethernet frame, as
|
||||
returned by "fc_saved_syn" combined with the "tcp-ss" bind option set to "2".
|
||||
It returns the protocol number (also known as EtherType) found in a Ethernet
|
||||
header after any optional VLAN as an integer value. It should normally be
|
||||
either 0x800 for IPv4 or 0x86DD for IPv6. See also "fc_saved_syn" and
|
||||
"tcp-ss".
|
||||
|
||||
eth.src
|
||||
This is used with an input sample representing a binary Ethernet frame, as
|
||||
returned by "fc_saved_syn" combined with the "tcp-ss" bind option set to "2".
|
||||
It returns the 6 bytes of the Ethernet header corresponding to the source
|
||||
address of the frame, as a binary block. See also "fc_saved_syn" and
|
||||
"tcp-ss".
|
||||
|
||||
eth.vlan
|
||||
This is used with an input sample representing a binary Ethernet frame, as
|
||||
returned by "fc_saved_syn" combined with the "tcp-ss" bind option set to "2".
|
||||
It returns the last VLAN ID found in a Ethernet header as an integer value.
|
||||
See also "fc_saved_syn" and "tcp-ss".
|
||||
|
||||
even
|
||||
Returns a boolean TRUE if the input value of type signed integer is even
|
||||
otherwise returns FALSE. It is functionally equivalent to "not,and(1),bool".
|
||||
|
|
@ -23921,7 +23969,8 @@ fc_saved_syn : binary
|
|||
0204FFC40402080A9C231D680000000001030307 # MSS=65476, TS, SACK, WSCALE 7
|
||||
|
||||
The "bytes()" converter helps extract specific fields from the packet. The
|
||||
be2dec() also permits to read chunks and emit them in integer form.
|
||||
be2dec() also permits to read chunks and emit them in integer form. For more
|
||||
accurate extraction, please refer to the "eth.XXX" converters.
|
||||
|
||||
Example with IPv4 input:
|
||||
|
||||
|
|
@ -23930,10 +23979,10 @@ fc_saved_syn : binary
|
|||
bind :4445 tcp-ss 2
|
||||
tcp-request connection set-var(sess.syn) fc_saved_syn
|
||||
http-request return status 200 content-type text/plain lf-string \
|
||||
"mac_dst=%[var(sess.syn),bytes(0,6),hex] \
|
||||
mac_src=%[var(sess.syn),bytes(6,6),hex] \
|
||||
proto=%[var(sess.syn),bytes(12,2),hex] \
|
||||
ipv4h=%[var(sess.syn),bytes(14,12),hex] \
|
||||
"mac_dst=%[var(sess.syn),eth.dst,hex] \
|
||||
mac_src=%[var(sess.syn),eth.src,hex] \
|
||||
proto=%[var(sess.syn),eth.proto,bytes(6),be2hex(,2)] \
|
||||
ipv4h=%[var(sess.syn),eth.data,bytes(0,12),hex] \
|
||||
ipv4_src=%[var(sess.syn),bytes(26,4),be2dec(.,1)] \
|
||||
ipv4_dst=%[var(sess.syn),bytes(30,4),be2dec(.,1)] \
|
||||
tcp_spt=%[var(sess.syn),bytes(34,2),be2dec(,2)] \
|
||||
|
|
@ -23947,7 +23996,8 @@ fc_saved_syn : binary
|
|||
tcp_spt=43970 tcp_dpt=4445 tcp_win=65495 \
|
||||
tcp_opt=0204FFD70402080A01DC0D410000000001030307
|
||||
|
||||
See also the "set-var" action, the "be2dec", "bytes" and "hex" converters.
|
||||
See also the "set-var" action, the "be2dec", "bytes", "hex", and
|
||||
"eth.XXX" converters.
|
||||
|
||||
fc_settings_streams_limit : integer
|
||||
Returns the maximum number of streams allowed on the frontend connection. For
|
||||
|
|
|
|||
134
src/net_helper.c
Normal file
134
src/net_helper.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <haproxy/api.h>
|
||||
#include <haproxy/arg.h>
|
||||
#include <haproxy/buf.h>
|
||||
#include <haproxy/cfgparse.h>
|
||||
#include <haproxy/chunk.h>
|
||||
#include <haproxy/errors.h>
|
||||
#include <haproxy/global.h>
|
||||
#include <haproxy/net_helper.h>
|
||||
#include <haproxy/sample.h>
|
||||
|
||||
/*****************************************************/
|
||||
/* Converters used to process Ethernet frame headers */
|
||||
/*****************************************************/
|
||||
|
||||
/* returns only the data part of an input ethernet frame header, skipping any
|
||||
* possible VLAN header. This is typically used to return the beginning of the
|
||||
* IP packet.
|
||||
*/
|
||||
static int sample_conv_eth_data(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
for (idx = 12; idx + 2 < smp->data.u.str.data; idx += 4) {
|
||||
if (read_n16(smp->data.u.str.area + idx) != 0x8100) {
|
||||
smp->data.u.str.area += idx + 2;
|
||||
smp->data.u.str.data -= idx + 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* incomplete header */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the 6 bytes of MAC DST address of an input ethernet frame header */
|
||||
static int sample_conv_eth_dst(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
|
||||
if (smp->data.u.str.data < 6)
|
||||
return 0;
|
||||
|
||||
smp->data.u.str.data = 6; // output length is 6
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns only the ethernet header for an input ethernet frame header,
|
||||
* including any possible VLAN headers, but stopping before data.
|
||||
*/
|
||||
static int sample_conv_eth_hdr(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
for (idx = 12; idx + 2 < smp->data.u.str.data; idx += 4) {
|
||||
if (read_n16(smp->data.u.str.area + idx) != 0x8100) {
|
||||
smp->data.u.str.data = idx + 2;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* incomplete header */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the ethernet protocol of an input ethernet frame header, skipping
|
||||
* any VLAN tag.
|
||||
*/
|
||||
static int sample_conv_eth_proto(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
ushort proto;
|
||||
size_t idx;
|
||||
|
||||
for (idx = 12; idx + 2 < smp->data.u.str.data; idx += 4) {
|
||||
proto = read_n16(smp->data.u.str.area + idx);
|
||||
if (proto != 0x8100) {
|
||||
smp->data.u.sint = proto;
|
||||
smp->data.type = SMP_T_SINT;
|
||||
smp->flags &= ~SMP_F_CONST;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* incomplete header */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* returns the 6 bytes of MAC SRC address of an input ethernet frame header */
|
||||
static int sample_conv_eth_src(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
|
||||
if (smp->data.u.str.data < 12)
|
||||
return 0;
|
||||
|
||||
smp->data.u.str.area += 6; // src is at address 6
|
||||
smp->data.u.str.data = 6; // output length is 6
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* returns the last VLAN ID seen in an input ethernet frame header, if any.
|
||||
* Note that VLAN ID 0 is considered as absence of VLAN.
|
||||
*/
|
||||
static int sample_conv_eth_vlan(const struct arg *arg_p, struct sample *smp, void *private)
|
||||
{
|
||||
ushort vlan = 0;
|
||||
size_t idx;
|
||||
|
||||
for (idx = 12; idx + 2 < smp->data.u.str.data; idx += 4) {
|
||||
if (read_n16(smp->data.u.str.area + idx) != 0x8100) {
|
||||
smp->data.u.sint = vlan;
|
||||
smp->data.type = SMP_T_SINT;
|
||||
smp->flags &= ~SMP_F_CONST;
|
||||
return !!vlan;
|
||||
}
|
||||
if (idx + 4 < smp->data.u.str.data)
|
||||
break;
|
||||
|
||||
vlan = read_n16(smp->data.u.str.area + idx + 2) & 0xfff;
|
||||
}
|
||||
/* incomplete header */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Note: must not be declared <const> as its list will be overwritten */
|
||||
static struct sample_conv_kw_list sample_conv_kws = {ILH, {
|
||||
{ "eth.data", sample_conv_eth_data, 0, NULL, SMP_T_BIN, SMP_T_BIN },
|
||||
{ "eth.dst", sample_conv_eth_dst, 0, NULL, SMP_T_BIN, SMP_T_BIN },
|
||||
{ "eth.hdr", sample_conv_eth_hdr, 0, NULL, SMP_T_BIN, SMP_T_BIN },
|
||||
{ "eth.proto", sample_conv_eth_proto, 0, NULL, SMP_T_BIN, SMP_T_SINT },
|
||||
{ "eth.src", sample_conv_eth_src, 0, NULL, SMP_T_BIN, SMP_T_BIN },
|
||||
{ "eth.vlan", sample_conv_eth_vlan, 0, NULL, SMP_T_BIN, SMP_T_SINT },
|
||||
|
||||
{ NULL, NULL, 0, 0, 0 },
|
||||
}};
|
||||
|
||||
INITCALL1(STG_REGISTER, sample_register_convs, &sample_conv_kws);
|
||||
Loading…
Reference in a new issue