It is quite tricky to set field value with a variable length
(i.e. DNS query name), to make it possible the field
needs to be added to header with 'len=0' in that case there
will be no any payload allocation, but only while setting the field
value the packet will be appended with a real length bytes and after
the field needs to be relocated to the right place.

Signed-off-by: Vadim Kochan <vadi...@gmail.com>
---
 trafgen_proto.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/trafgen_proto.c b/trafgen_proto.c
index 0530032..83a6a7e 100644
--- a/trafgen_proto.c
+++ b/trafgen_proto.c
@@ -100,6 +100,9 @@ void proto_header_fields_add(struct proto_hdr *hdr,
                f->pkt_offset = hdr->pkt_offset + fields[i].offset;
                f->hdr = hdr;
 
+               if (!f->len)
+                       continue;
+
                if (f->pkt_offset + f->len > pkt->len) {
                        hdr->len += f->len;
                        set_fill(0, (f->pkt_offset + f->len) - pkt->len);
@@ -181,6 +184,45 @@ set_proto:
        return current;
 }
 
+static void __proto_field_relocate(struct proto_field *field)
+{
+       struct proto_hdr *hdr = field->hdr;
+       struct packet *pkt = packet_get(hdr->pkt_id);
+       uint8_t *from, *to;
+       int i;
+
+       /* If this is a last field then just calculate 'pkt_offset' */
+       if (field->id == hdr->fields_count - 1) {
+               field->pkt_offset = hdr->pkt_offset + hdr->len - field->len;
+               return;
+       }
+
+       /* Use 'pkt_offset' from the 1st real (len > 0) field after the
+        * 'target' one */
+       for (i = field->id + 1; i < hdr->fields_count; i++) {
+               if (hdr->fields[i].len == 0)
+                       continue;
+
+               field->pkt_offset = hdr->fields[i].pkt_offset;
+               break;
+       }
+
+       /* Move payload of overlapped fields (each after the 'target' field) */
+       from = &pkt->payload[field->pkt_offset];
+       to = &pkt->payload[field->pkt_offset + field->len];
+       memcpy(to, from, hdr->len - field->len);
+
+       /* Recalculate 'pkt_offset' of the rest fields */
+       for (; i < hdr->fields_count; i++) {
+               struct proto_field *tmp = &hdr->fields[i];
+
+               if (tmp->len == 0)
+                       continue;
+
+               tmp->pkt_offset += field->len;
+       }
+}
+
 static void __proto_field_set_bytes(struct proto_field *field,
                                    const uint8_t *bytes, size_t len,
                                    bool is_default, bool is_be)
@@ -195,6 +237,14 @@ static void __proto_field_set_bytes(struct proto_field 
*field,
        if (is_default && field->is_set)
                return;
 
+       if (field->len == 0) {
+               field->hdr->len += len;
+               field->len = len;
+               set_fill(0, len);
+
+               __proto_field_relocate(field);
+       }
+
        payload = &packet_get(field->hdr->pkt_id)->payload[field->pkt_offset];
 
        if (field->len == 1) {
-- 
2.11.0

-- 
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