Add Ethernet packet generation via command line:
    trafgen --dev eth0 eth sa=af:cd:4b:c3:56:6a da=af:cd:4b:c3:56:6a 
proto=0x0800

Added separated layer2_gen.c module which will contain L2 related proto
generators.

By default source MAC address is used from specified device, and
destination MAC address is broadcast FF:FF:FF:FF:FF:FF.

Signed-off-by: Vadim Kochan <vadi...@gmail.com>
---
 layer2_gen.c     | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 proto_gen.c      |   3 ++
 trafgen/Makefile |   2 +
 3 files changed, 150 insertions(+)
 create mode 100644 layer2_gen.c

diff --git a/layer2_gen.c b/layer2_gen.c
new file mode 100644
index 0000000..a338dbd
--- /dev/null
+++ b/layer2_gen.c
@@ -0,0 +1,145 @@
+/*
+ * netsniff-ng - the packet sniffing beast
+ * Subject to the GPL, version 2.
+ */
+
+#include <net/if_arp.h>
+#include <linux/if_ether.h>
+
+#include "dev.h"
+#include "xmalloc.h"
+#include "net_utils.h"
+#include "proto_gen.h"
+
+#define ETH_BCAST_ADDR { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }
+
+enum eth_field {
+       ETH_DST_ADDR,
+       ETH_SRC_ADDR,
+       ETH_PROTO_ID,
+};
+
+static void eth_set_proto_field(struct proto_gen *prot, int proto_id)
+{
+       if (!proto_field_exist(prot, ETH_PROTO_ID))
+               proto_field_add(prot, ETH_PROTO_ID, 2);
+
+       proto_field_set_value(prot, ETH_PROTO_ID, proto_id);
+}
+
+static int eth_parse_param(struct proto_gen *prot, char *name, char *val)
+{
+       uint8_t addr[6] = {};
+
+       if (!strcasecmp("dst", name) || !strcasecmp("da", name)) {
+               int ret = str2mac(val, &addr[0]);
+               proto_field_set_bytes(prot, ETH_DST_ADDR, &addr[0]);
+
+               return ret == 0 ? ETH_DST_ADDR : -1;
+       }
+
+       if (!strcasecmp("src", name) || !strcasecmp("sa", name)) {
+               int ret = str2mac(val, &addr[0]);
+               proto_field_set_bytes(prot, ETH_SRC_ADDR, &addr[0]);
+
+               return ret == 0 ? ETH_SRC_ADDR : -1;
+       }
+
+       if (!strcasecmp("type", name) || !strcasecmp("proto", name)) {
+               char *ptr = NULL;
+               int proto_id = htons(strtol(val, &ptr, 0));
+
+               if (errno == ERANGE || errno == EINVAL || ptr == val)
+                       return -1;
+
+               eth_set_proto_field(prot, proto_id);
+               return ETH_PROTO_ID;
+       }
+
+       return -1;
+}
+
+static void eth_set_next_proto(struct proto_gen *prot, struct proto_gen *next)
+{
+       int proto_id = 0;
+
+       switch (next->id) {
+       case NET_PROTO_ARP:
+               proto_id = ETH_P_ARP;
+               break;
+       case NET_PROTO_IPV4:
+               proto_id = ETH_P_IP;
+               break;
+       case NET_PROTO_IPV6:
+               proto_id = ETH_P_IPV6;
+               break;
+       case NET_PROTO_NONE:
+       case NET_PROTO_ETH:
+       case NET_PROTO_UDP:
+       case NET_PROTO_TCP:
+               break;
+       }
+
+       eth_set_proto_field(prot, htons(proto_id));
+}
+
+static void eth_print_help(struct proto_gen *prot)
+{
+#define ETH_PROT_HELP \
+       "| eth proto: Sends Ethernet packets.\n" \
+       "| Parameters:\n" \
+       "|\n" \
+       "|    src,sa = XX:XX:XX:XX:XX:XX               ..... Source MAC 
address\n" \
+       "|    dst,da = XX:XX:XX:XX:XX:XX               ..... Destination MAC 
address\n" \
+       "|    proto,type = decimal | 0xXXX             ..... Sets 
proto/type/len value\n" \
+       "|    data,payload = hexadecimal               ..... Binary payload 
data\n" \
+       "|    text = ascii string                      ..... Textual payload 
data\n" \
+       "|\n" \
+       "| EXAMPLES:\n" \
+       "|      trafgen --dev eth0 eth sa=af:cd:4b:c3:56:6a 
da=af:cd:4b:c3:56:6a proto=0x0800\n" \
+       "|\n" \
+       "\n"
+
+       printf(ETH_PROT_HELP);
+}
+
+static void eth_check_fields(struct proto_gen *prot)
+{
+       if (!proto_field_is_set(prot, ETH_DST_ADDR)) {
+               uint8_t bcast[6] = ETH_BCAST_ADDR;
+
+               proto_field_set_bytes(prot, ETH_DST_ADDR, &bcast[0]);
+       }
+
+       if (!proto_field_is_set(prot, ETH_SRC_ADDR)) {
+               uint8_t addr[6] = {0};
+
+               if (!device_hw_address(prot->ctx->device, &addr[0]))
+                       proto_field_set_bytes(prot, ETH_SRC_ADDR, &addr[0]);
+       }
+}
+
+static void eth_proto_init(struct proto_gen *prot)
+{
+       proto_field_add(prot, ETH_DST_ADDR, 6);
+       proto_field_add(prot, ETH_SRC_ADDR, 6);
+
+       /* Do not add proto field here as it can be set
+        * from specified payload or after vlan headers */
+}
+
+static struct proto_gen eth_gen = {
+       .id             = NET_PROTO_ETH,
+       .name           = "eth",
+       .min_size       = 15,
+       .proto_init     = eth_proto_init,
+       .parse_param    = eth_parse_param,
+       .set_next_proto = eth_set_next_proto,
+       .print_help     = eth_print_help,
+       .check_fields   = eth_check_fields,
+};
+
+void layer2_gen_register(void)
+{
+       proto_gen_register(&eth_gen);
+}
diff --git a/proto_gen.c b/proto_gen.c
index eee6227..1abebab 100644
--- a/proto_gen.c
+++ b/proto_gen.c
@@ -11,6 +11,8 @@
 
 static struct proto_gen *protos;
 
+extern void layer2_gen_register(void);
+
 struct proto_gen *proto_gen_by_name(char *name)
 {
        struct proto_gen *p = protos;
@@ -41,6 +43,7 @@ void proto_gen_register(struct proto_gen *prot)
 
 void proto_gen_init(void)
 {
+       layer2_gen_register();
 }
 
 void proto_gen_uninit(void)
diff --git a/trafgen/Makefile b/trafgen/Makefile
index c935c0b..723cd8d 100644
--- a/trafgen/Makefile
+++ b/trafgen/Makefile
@@ -18,6 +18,8 @@ trafgen-objs =        xmalloc.o \
                ring.o \
                timer.o \
                proto_gen.o \
+               net_utils.o \
+               layer2_gen.o \
                trafgen_lexer.yy.o \
                trafgen_parser.tab.o \
                trafgen.o
-- 
2.4.2

-- 
You received this message because you are subscribed to the Google Groups 
"netsniff-ng" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to netsniff-ng+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to