pespin has submitted this change. ( 
https://gerrit.osmocom.org/c/osmo-pcap/+/39288?usp=email )

Change subject: client: Introduce osmo_pcap_file to prepare support for pcapng
......................................................................

client: Introduce osmo_pcap_file to prepare support for pcapng

This patch is a preparation patch refactoring code to make it easier to
add pcapng format in follow-up patch.

Different types of encodings are grouped in helper functions.

Change-Id: Ifd389a2a32897e101c62fd280ddca984d485d373
---
M include/osmo-pcap/Makefile.am
M include/osmo-pcap/osmo_pcap_client.h
A include/osmo-pcap/osmo_pcap_file.h
M src/Makefile.am
M src/osmo_client_core.c
M src/osmo_client_network.c
A src/osmo_pcap_file.c
7 files changed, 240 insertions(+), 78 deletions(-)

Approvals:
  laforge: Looks good to me, but someone else must approve
  pespin: Looks good to me, approved
  Jenkins Builder: Verified
  osmith: Looks good to me, but someone else must approve




diff --git a/include/osmo-pcap/Makefile.am b/include/osmo-pcap/Makefile.am
index e377b6a..58c8a59 100644
--- a/include/osmo-pcap/Makefile.am
+++ b/include/osmo-pcap/Makefile.am
@@ -1,6 +1,7 @@
 noinst_HEADERS = \
        common.h \
        osmo_pcap_client.h \
+       osmo_pcap_file.h \
        osmo_pcap_server.h \
        osmo_tls.h \
        wireformat.h \
diff --git a/include/osmo-pcap/osmo_pcap_client.h 
b/include/osmo-pcap/osmo_pcap_client.h
index 442244e..470edb6 100644
--- a/include/osmo-pcap/osmo_pcap_client.h
+++ b/include/osmo-pcap/osmo_pcap_client.h
@@ -139,7 +139,9 @@
 struct osmo_pcap_client_conn *osmo_client_conn_alloc(struct osmo_pcap_client 
*client, const char *name);
 void osmo_client_conn_free(struct osmo_pcap_client_conn *conn);
 void osmo_client_conn_send_data(struct osmo_pcap_client_conn *conn,
-                               struct pcap_pkthdr *hdr, const uint8_t *data);
+                               const struct osmo_pcap_handle *ph,
+                               const struct pcap_pkthdr *pkthdr,
+                               const uint8_t *data);
 void osmo_client_conn_send_link(struct osmo_pcap_client_conn *conn);
 void osmo_client_conn_connect(struct osmo_pcap_client_conn *conn);
 void osmo_client_conn_disconnect(struct osmo_pcap_client_conn *conn);
diff --git a/include/osmo-pcap/osmo_pcap_file.h 
b/include/osmo-pcap/osmo_pcap_file.h
new file mode 100644
index 0000000..50a7706
--- /dev/null
+++ b/include/osmo-pcap/osmo_pcap_file.h
@@ -0,0 +1,37 @@
+/*
+ * Procedures to operate on pcap/pcapng file format
+ *
+ * (C) 2025 by sysmocom - s.f.m.c. GmbH <[email protected]>
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#pragma once
+
+#include <unistd.h>
+#include <stdint.h>
+
+/***********************************************************
+* Libpcap File Format (.pcap)
+* https://wiki.wireshark.org/Development/LibpcapFileFormat
+***********************************************************/
+
+#define OSMO_PCAP_FILE_MAGIC 0xa1b2c3d4
+
+int osmo_pcap_file_msgb_append_global_header(struct msgb *msg, uint32_t 
snaplen, uint32_t linktype);
+
+unsigned int osmo_pcap_file_record_size(const struct pcap_pkthdr *in_hdr);
+int osmo_pcap_file_msgb_append_record(struct msgb *msg, const struct 
pcap_pkthdr *in_hdr, const uint8_t *data);
diff --git a/src/Makefile.am b/src/Makefile.am
index 00c9ce9..bb70d21 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,6 +20,7 @@
        osmo_client_network.c \
        osmo_client_stats.c \
        osmo_client_vty.c \
+       osmo_pcap_file.c \
        osmo_tls.c \
        $(NULL)

diff --git a/src/osmo_client_core.c b/src/osmo_client_core.c
index a2ab894..538b68a 100644
--- a/src/osmo_client_core.c
+++ b/src/osmo_client_core.c
@@ -172,7 +172,7 @@
                return 0;

        llist_for_each_entry(conn, &client->conns, entry)
-               osmo_client_conn_send_data(conn, &hdr, data);
+               osmo_client_conn_send_data(conn, ph, &hdr, data);
        return 0;
 }

diff --git a/src/osmo_client_network.c b/src/osmo_client_network.c
index 70fe740..e14f4ca 100644
--- a/src/osmo_client_network.c
+++ b/src/osmo_client_network.c
@@ -1,6 +1,7 @@
 /*
  * osmo-pcap-client code
  *
+ * (C) 2025 by sysmocom - s.f.m.c. GmbH <[email protected]>
  * (C) 2011-2016 by Holger Hans Peter Freyther <[email protected]>
  * (C) 2011 by On-Waves
  * All Rights Reserved
@@ -23,7 +24,9 @@
 #include <osmo-pcap/osmo_pcap_client.h>
 #include <osmo-pcap/common.h>
 #include <osmo-pcap/wireformat.h>
+#include <osmo-pcap/osmo_pcap_file.h>

+#include <osmocom/core/utils.h>
 #include <osmocom/core/msgb.h>
 #include <osmocom/core/rate_ctr.h>
 #include <osmocom/core/select.h>
@@ -160,112 +163,152 @@
        }
 }

-void osmo_client_conn_send_data(struct osmo_pcap_client_conn *conn,
-                               struct pcap_pkthdr *in_hdr, const uint8_t *data)
+static struct msgb *osmo_client_conn_prepare_msg_data_pcap(struct 
osmo_pcap_client_conn *conn,
+                                                          const struct 
osmo_pcap_handle *ph,
+                                                          const struct 
pcap_pkthdr *pkthdr,
+                                                          const uint8_t *data)
 {
        struct osmo_pcap_data *om_hdr;
-       struct osmo_pcap_pkthdr *hdr;
        struct msgb *msg;
-       int offset, ip_len;
-       struct osmo_pcap_handle *ph;
+       unsigned int record_size = osmo_pcap_file_record_size(pkthdr);

-       if (in_hdr->len > in_hdr->caplen) {
-               LOGCONN(conn, LOGL_ERROR, "Recording truncated packet, len %zu 
> snaplen %zu\n",
-                       (size_t) in_hdr->len, (size_t) in_hdr->caplen);
-               rate_ctr_inc2(conn->client->ctrg, CLIENT_CTR_2BIG);
-       }
-
-       msg = msgb_alloc(in_hdr->caplen + sizeof(*om_hdr) + sizeof(*hdr), 
"data-data");
+       msg = msgb_alloc(sizeof(*om_hdr) + record_size, "pcap-data");
        if (!msg) {
                LOGCONN(conn, LOGL_ERROR, "Failed to allocate\n");
                rate_ctr_inc2(conn->client->ctrg, CLIENT_CTR_NOMEM);
-               return;
+               return NULL;
+       }
+
+       om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
+       om_hdr->type = PKT_LINK_DATA;
+       om_hdr->len = htons(record_size);
+       osmo_pcap_file_msgb_append_record(msg, pkthdr, data);
+
+       return msg;
+}
+
+static struct msgb *osmo_client_conn_prepare_msg_ipip(struct 
osmo_pcap_client_conn *conn,
+                                                     const struct 
osmo_pcap_handle *ph,
+                                                     const struct pcap_pkthdr 
*pkthdr,
+                                                     const uint8_t *data)
+{
+       struct msgb *msg;
+       int offset, ip_len;
+
+       offset = get_iphdr_offset(pcap_datalink(ph->handle));
+       if (offset < 0)
+               return NULL;
+
+       ip_len = pkthdr->caplen - offset;
+       if (ip_len < 0)
+               return NULL;
+
+
+       msg = msgb_alloc(ip_len, "ipip_msg");
+       if (!msg) {
+               LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
+               rate_ctr_inc2(conn->client->ctrg, CLIENT_CTR_NOMEM);
+               return NULL;
+       }
+       msg->l2h = msgb_put(msg, ip_len);
+       memcpy(msg->l2h, data+offset, ip_len);
+       return msg;
+}
+
+void osmo_client_conn_send_data(struct osmo_pcap_client_conn *conn,
+                               const struct osmo_pcap_handle *ph,
+                               const struct pcap_pkthdr *pkthdr,
+                               const uint8_t *data)
+{
+       struct osmo_pcap_client *client = conn->client;
+       struct msgb *msg;
+
+       if (pkthdr->len > pkthdr->caplen) {
+               LOGCONN(conn, LOGL_ERROR, "Recording truncated packet, len %zu 
> snaplen %zu\n",
+                       (size_t) pkthdr->len, (size_t) pkthdr->caplen);
+               rate_ctr_inc2(client->ctrg, CLIENT_CTR_2BIG);
        }

        switch (conn->protocol) {
        case PROTOCOL_OSMOPCAP:
-               om_hdr = (struct osmo_pcap_data *) msgb_put(msg, 
sizeof(*om_hdr));
-               om_hdr->type = PKT_LINK_DATA;
-
-               msg->l2h = msgb_put(msg, sizeof(*hdr));
-               hdr = (struct osmo_pcap_pkthdr *) msg->l2h;
-               hdr->ts_sec = in_hdr->ts.tv_sec;
-               hdr->ts_usec = in_hdr->ts.tv_usec;
-               hdr->caplen = in_hdr->caplen;
-               hdr->len = in_hdr->len;
-
-               msg->l3h = msgb_put(msg, in_hdr->caplen);
-               memcpy(msg->l3h, data, in_hdr->caplen);
-
-               om_hdr->len = htons(msgb_l2len(msg));
-               rate_ctr_add2(conn->client->ctrg, CLIENT_CTR_BYTES, 
hdr->caplen);
-               rate_ctr_inc2(conn->client->ctrg, CLIENT_CTR_PKTS);
+               msg = osmo_client_conn_prepare_msg_data_pcap(conn, ph, pkthdr, 
data);
                break;
        case PROTOCOL_IPIP:
-               /* TODO: support capturing from multiple interfaces here: */
-               ph = llist_first_entry_or_null(&conn->client->handles, struct 
osmo_pcap_handle, entry);
-               if (!ph) {
-                       msgb_free(msg);
-                       return;
-               }
-               offset = get_iphdr_offset(pcap_datalink(ph->handle));
-               if (offset < 0) {
-                       msgb_free(msg);
-                       return;
-               }
-               ip_len = in_hdr->caplen - offset;
-               if (ip_len < 0) {
-                       msgb_free(msg);
-                       return;
-               }
-               msg->l2h = msgb_put(msg, ip_len);
-               memcpy(msg->l2h, data+offset, ip_len);
+               msg = osmo_client_conn_prepare_msg_ipip(conn, ph, pkthdr, data);
                break;
        default:
                OSMO_ASSERT(0);
        }

+       if (!msg)
+               return;
+
+       rate_ctr_add2(conn->client->ctrg, CLIENT_CTR_BYTES, pkthdr->caplen);
+       rate_ctr_inc2(conn->client->ctrg, CLIENT_CTR_PKTS);
+
        write_data(conn, msg);
 }

+static struct msgb *osmo_client_conn_prepare_msg_link_pcap(struct 
osmo_pcap_client_conn *conn)
+{
+       struct osmo_pcap_client *client = conn->client;
+       struct osmo_pcap_data *om_hdr;
+       struct msgb *msg;
+       struct osmo_pcap_handle *ph;
+       int rc;
+       int linktype;
+
+       ph = llist_first_entry_or_null(&client->handles, struct 
osmo_pcap_handle, entry);
+       if (!ph || !ph->handle) {
+               LOGCONN(conn, LOGL_ERROR, "No pcap_handle not sending link 
info\n");
+               return NULL;
+       }
+       linktype = pcap_datalink(ph->handle);
+
+       /* Make sure others have same linktype, .pcap doesn't support different
+        * linktypes since traffic from all ifaces goes mixed together. */
+       llist_for_each_entry(ph, &client->handles, entry) {
+               if (linktype != pcap_datalink(ph->handle)) {
+                       LOGCONN(conn, LOGL_ERROR,
+                               "File format 'pcap' doesn't support recording 
from multiple ifaces "
+                               "with different link types!\n");
+                       return NULL;
+               }
+       }
+
+       msg = msgb_alloc(sizeof(*om_hdr) + sizeof(struct pcap_file_header), 
"link-data");
+       if (!msg) {
+               LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
+               return NULL;
+       }
+
+
+       om_hdr = (struct osmo_pcap_data *)msgb_put(msg, sizeof(*om_hdr));
+       om_hdr->type = PKT_LINK_HDR;
+
+       rc = osmo_pcap_file_msgb_append_global_header(msg, client->snaplen, 
linktype);
+       if (rc < 0) {
+               LOGP(DCLIENT, LOGL_ERROR, "Failed to create pcap file global 
header.\n");
+               msgb_free(msg);
+               return NULL;
+       }
+
+       /* Update payload length: */
+       om_hdr->len = htons(rc);
+       return msg;
+}
+
 void osmo_client_conn_send_link(struct osmo_pcap_client_conn *conn)
 {
-       struct osmo_pcap_handle *ph;
-       struct pcap_file_header *hdr;
-       struct osmo_pcap_data *om_hdr;
        struct msgb *msg;

        /* IPIP encapsulation has no linktype header */
        if (conn->protocol == PROTOCOL_IPIP)
                return;

-       /* TODO: support capturing from multiple interfaces here: */
-       ph = llist_first_entry_or_null(&conn->client->handles, struct 
osmo_pcap_handle, entry);
-       if (!ph || !ph->handle) {
-               LOGCONN(conn, LOGL_ERROR, "No pcap_handle not sending link 
info\n");
+       msg = osmo_client_conn_prepare_msg_link_pcap(conn);
+       if (!msg)
                return;
-       }
-
-       msg = msgb_alloc(sizeof(*om_hdr) + sizeof(*hdr), "link-data");
-       if (!msg) {
-               LOGP(DCLIENT, LOGL_ERROR, "Failed to allocate data.\n");
-               return;
-       }
-
-
-       om_hdr = (struct osmo_pcap_data *) msgb_put(msg, sizeof(*om_hdr));
-       om_hdr->type = PKT_LINK_HDR;
-       om_hdr->len = htons(sizeof(*hdr));
-
-       hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
-       hdr->magic = 0xa1b2c3d4;
-       hdr->version_major = 2;
-       hdr->version_minor = 4;
-       hdr->thiszone = 0;
-       hdr->sigfigs = 0;
-       hdr->snaplen = conn->client->snaplen;
-       hdr->linktype = pcap_datalink(ph->handle);
-
        write_data(conn, msg);
 }

diff --git a/src/osmo_pcap_file.c b/src/osmo_pcap_file.c
new file mode 100644
index 0000000..eb8cc23
--- /dev/null
+++ b/src/osmo_pcap_file.c
@@ -0,0 +1,78 @@
+/*
+ * osmo-pcap-client code
+ *
+ * (C) 2025 by sysmocom - s.f.m.c. GmbH <[email protected]>
+ * (C) 2011-2016 by Holger Hans Peter Freyther <[email protected]>
+ * (C) 2011 by On-Waves
+ * All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <pcap/pcap.h>
+
+#include <osmocom/core/msgb.h>
+
+#include <osmo-pcap/osmo_pcap_file.h>
+#include <osmo-pcap/common.h>
+#include <osmo-pcap/wireformat.h>
+
+/***********************************************************
+ * Libpcap File Format (.pcap)
+ * https://wiki.wireshark.org/Development/LibpcapFileFormat
+ ***********************************************************/
+
+/* Appends a Global Header to msg
+ * returns number of bytes appended on success, negative on error */
+int osmo_pcap_file_msgb_append_global_header(struct msgb *msg, uint32_t 
snaplen, uint32_t linktype)
+{
+       struct pcap_file_header *hdr;
+
+       hdr = (struct pcap_file_header *) msgb_put(msg, sizeof(*hdr));
+       hdr->magic = OSMO_PCAP_FILE_MAGIC;
+       hdr->version_major = 2;
+       hdr->version_minor = 4;
+       hdr->thiszone = 0;
+       hdr->sigfigs = 0;
+       hdr->snaplen = snaplen;
+       hdr->linktype = linktype;
+
+       return sizeof(*hdr);
+}
+
+/* Get required length to store a given record (packet) */
+unsigned int osmo_pcap_file_record_size(const struct pcap_pkthdr *in_hdr)
+{
+       return sizeof(struct osmo_pcap_pkthdr) + in_hdr->caplen;
+}
+
+/* Appends a Record (Packet) Header to msg
+ * returns number of bytes appended on success, negative on error */
+int osmo_pcap_file_msgb_append_record(struct msgb *msg, const struct 
pcap_pkthdr *in_hdr, const uint8_t *data)
+{
+       struct osmo_pcap_pkthdr *hdr;
+       uint8_t *pkt_payload;
+
+       hdr = (struct osmo_pcap_pkthdr *) msgb_put(msg, sizeof(*hdr));
+       hdr->ts_sec = in_hdr->ts.tv_sec;
+       hdr->ts_usec = in_hdr->ts.tv_usec;
+       hdr->caplen = in_hdr->caplen;
+       hdr->len = in_hdr->len;
+
+       pkt_payload = msgb_put(msg, in_hdr->caplen);
+       memcpy(pkt_payload, data, in_hdr->caplen);
+
+       return osmo_pcap_file_record_size(in_hdr);
+}

--
To view, visit https://gerrit.osmocom.org/c/osmo-pcap/+/39288?usp=email
To unsubscribe, or for help writing mail filters, visit 
https://gerrit.osmocom.org/settings?usp=email

Gerrit-MessageType: merged
Gerrit-Project: osmo-pcap
Gerrit-Branch: master
Gerrit-Change-Id: Ifd389a2a32897e101c62fd280ddca984d485d373
Gerrit-Change-Number: 39288
Gerrit-PatchSet: 2
Gerrit-Owner: pespin <[email protected]>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: laforge <[email protected]>
Gerrit-Reviewer: osmith <[email protected]>
Gerrit-Reviewer: pespin <[email protected]>

Reply via email to