aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHarald Welte <laforge@gnumonks.org>2017-07-21 18:12:01 +0200
committerHarald Welte <laforge@gnumonks.org>2017-07-21 18:42:22 +0200
commitabc6dd83bc27da426f463919567784a44ed99fa7 (patch)
treedfbccba8f19579160086ab20c14d5e499bd956cd
parent5f071cd2c6af6c840d5ecac8e8474067fdc5738c (diff)
Add support for generating IPIP to osmo-pcap-clientlaforge/ipip
This allows the user to change the configuration between either using a) the classic OsmoPCAP protocol (over TCP with or without TLS) which is used when you want to talk to an osmo-pcap-server b) the (new) IPIP encapsulation, which will simply take the IP packet (without Ethernet or pcap header) and transmit it inside IPIP to the specified server IP address. This is useful for gettin real-time streaming into wireshark. Change-Id: I8056fc163ac2f15adcb964d867dd5e51df4e4710
-rw-r--r--include/osmo-pcap/osmo_pcap_client.h6
-rw-r--r--src/osmo_client_network.c98
-rw-r--r--src/osmo_client_vty.c40
3 files changed, 124 insertions, 20 deletions
diff --git a/include/osmo-pcap/osmo_pcap_client.h b/include/osmo-pcap/osmo_pcap_client.h
index b4dda78..7888dfe 100644
--- a/include/osmo-pcap/osmo_pcap_client.h
+++ b/include/osmo-pcap/osmo_pcap_client.h
@@ -46,6 +46,11 @@ enum {
CLIENT_CTR_P_IFDROP,
};
+enum osmo_pcap_protocol {
+ PROTOCOL_OSMOPCAP,
+ PROTOCOL_IPIP,
+};
+
struct osmo_pcap_client_conn {
struct llist_head entry;
const char *name;
@@ -55,6 +60,7 @@ struct osmo_pcap_client_conn {
char *source_ip;
struct osmo_wqueue wqueue;
struct osmo_timer_list timer;
+ enum osmo_pcap_protocol protocol;
/* TLS handling */
bool tls_on;
diff --git a/src/osmo_client_network.c b/src/osmo_client_network.c
index 402e1cb..ec03b09 100644
--- a/src/osmo_client_network.c
+++ b/src/osmo_client_network.c
@@ -150,12 +150,25 @@ int conn_cb(struct osmo_fd *fd, unsigned int what)
return 0;
}
+static int get_iphdr_offset(int dlt)
+{
+ switch (dlt) {
+ case DLT_EN10MB:
+ return 14;
+ case DLT_LINUX_SLL:
+ return 16;
+ default:
+ return -1;
+ }
+}
+
void osmo_client_send_data(struct osmo_pcap_client_conn *conn,
struct pcap_pkthdr *in_hdr, const uint8_t *data)
{
struct osmo_pcap_data *om_hdr;
struct osmo_pcap_pkthdr *hdr;
struct msgb *msg;
+ int offset, ip_len;
if (in_hdr->caplen > 9000) {
LOGP(DCLIENT, LOGL_ERROR,
@@ -171,22 +184,42 @@ void osmo_client_send_data(struct osmo_pcap_client_conn *conn,
return;
}
- 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_add(&conn->client->ctrg->ctr[CLIENT_CTR_BYTES], hdr->caplen);
- rate_ctr_inc(&conn->client->ctrg->ctr[CLIENT_CTR_PKTS]);
+ 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_add(&conn->client->ctrg->ctr[CLIENT_CTR_BYTES], hdr->caplen);
+ rate_ctr_inc(&conn->client->ctrg->ctr[CLIENT_CTR_PKTS]);
+ break;
+ case PROTOCOL_IPIP:
+ offset = get_iphdr_offset(pcap_datalink(conn->client->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);
+ break;
+ default:
+ OSMO_ASSERT(0);
+ }
write_data(conn, msg);
}
@@ -197,6 +230,10 @@ void osmo_client_send_link(struct osmo_pcap_client_conn *conn)
struct osmo_pcap_data *om_hdr;
struct msgb *msg;
+ /* IPIP encapsulation has no linktype header */
+ if (conn->protocol == PROTOCOL_IPIP)
+ return;
+
if (!conn->client->handle) {
LOGP(DCLIENT, LOGL_ERROR,
"No pcap_handle not sending link info to conn=%s\n", conn->name);
@@ -229,6 +266,8 @@ void osmo_client_send_link(struct osmo_pcap_client_conn *conn)
void osmo_client_connect(struct osmo_pcap_client_conn *conn)
{
int rc;
+ uint16_t srv_port;
+ int sock_type, sock_proto;
osmo_client_disconnect(conn);
@@ -236,9 +275,25 @@ void osmo_client_connect(struct osmo_pcap_client_conn *conn)
conn->wqueue.write_cb = write_cb;
osmo_wqueue_clear(&conn->wqueue);
- rc = osmo_sock_init2_ofd(&conn->wqueue.bfd, AF_INET, SOCK_STREAM, IPPROTO_TCP,
- conn->source_ip, 0,
- conn->srv_ip, conn->srv_port,
+ switch (conn->protocol) {
+ case PROTOCOL_OSMOPCAP:
+ srv_port = conn->srv_port;
+ sock_type = SOCK_STREAM;
+ sock_proto = IPPROTO_TCP;
+ break;
+ case PROTOCOL_IPIP:
+ srv_port = 0;
+ sock_type = SOCK_RAW;
+ sock_proto = IPPROTO_IPIP;
+ conn->wqueue.bfd.when = BSC_FD_WRITE;
+ break;
+ default:
+ OSMO_ASSERT(0);
+ break;
+ }
+
+ rc = osmo_sock_init2_ofd(&conn->wqueue.bfd, AF_INET, sock_type, sock_proto,
+ conn->source_ip, 0, conn->srv_ip, srv_port,
OSMO_SOCK_F_BIND | OSMO_SOCK_F_CONNECT | OSMO_SOCK_F_NONBLOCK);
if (rc < 0) {
LOGP(DCLIENT, LOGL_ERROR,
@@ -251,7 +306,10 @@ void osmo_client_connect(struct osmo_pcap_client_conn *conn)
rate_ctr_inc(&conn->client->ctrg->ctr[CLIENT_CTR_CONNECT]);
conn->wqueue.bfd.cb = conn_cb;
conn->wqueue.bfd.data = conn;
- conn->wqueue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
+ if (conn->protocol == PROTOCOL_IPIP)
+ conn->wqueue.bfd.when = BSC_FD_WRITE;
+ else
+ conn->wqueue.bfd.when = BSC_FD_READ | BSC_FD_WRITE;
}
void osmo_client_reconnect(struct osmo_pcap_client_conn *conn)
diff --git a/src/osmo_client_vty.c b/src/osmo_client_vty.c
index 4cd2908..29f7051 100644
--- a/src/osmo_client_vty.c
+++ b/src/osmo_client_vty.c
@@ -31,6 +31,12 @@
#define PCAP_STRING "PCAP related functions\n"
#define SERVER_STRING "Server string\n"
+static const struct value_string osmopcap_protocol_names[] = {
+ { PROTOCOL_OSMOPCAP, "osmo-pcap" },
+ { PROTOCOL_IPIP, "ipip" },
+ { 0, NULL }
+};
+
static struct osmo_pcap_client_conn *get_conn(struct vty *vty)
{
if (vty->node == CLIENT_NODE)
@@ -94,6 +100,10 @@ static void write_client_conn_data(
if (conn->source_ip)
vty_out(vty, "%s source ip %s%s", indent,
conn->source_ip, VTY_NEWLINE);
+
+ if (conn->protocol != PROTOCOL_OSMOPCAP)
+ vty_out(vty, "%s protocol %s%s", indent,
+ get_value_string(osmopcap_protocol_names, conn->protocol), VTY_NEWLINE);
}
static int config_write_server(struct vty *vty)
@@ -466,6 +476,34 @@ DEFUN(cfg_client_disconnect,
return CMD_SUCCESS;
}
+#define PROTOCOL_STR "protocol (osmo-pcap|ipip)"
+#define PROTOCOL_HELP "Configure the Protocol used for transfer\n" \
+ "OsmoPCAP protocol (over TCP)\n" \
+ "IPIP encapsulation (for real-time streaming to wireshark)\n"
+
+DEFUN(cfg_protocol,
+ cfg_protocol_cmd,
+ PROTOCOL_STR,
+ PROTOCOL_HELP)
+{
+ struct osmo_pcap_client_conn *conn = get_conn(vty);
+
+ conn->protocol = get_string_value(osmopcap_protocol_names, argv[0]);
+ return CMD_SUCCESS;
+}
+
+DEFUN(cfg_client_protocol,
+ cfg_client_protocol_cmd,
+ PROTOCOL_STR,
+ PROTOCOL_HELP)
+{
+ struct osmo_pcap_client_conn *conn = get_conn(vty);
+
+ conn->protocol = get_string_value(osmopcap_protocol_names, argv[0]);
+ return CMD_SUCCESS;
+}
+
+
int vty_client_init(struct osmo_pcap_client *pcap)
{
install_element(CONFIG_NODE, &cfg_client_cmd);
@@ -482,6 +520,7 @@ int vty_client_init(struct osmo_pcap_client *pcap)
install_element(CLIENT_NODE, &cfg_server_ip_cmd);
install_element(CLIENT_NODE, &cfg_server_port_cmd);
install_element(CLIENT_NODE, &cfg_source_ip_cmd);
+ install_element(CLIENT_NODE, &cfg_protocol_cmd);
install_element(CLIENT_NODE, &cfg_enable_tls_cmd);
install_element(CLIENT_NODE, &cfg_disable_tls_cmd);
@@ -526,6 +565,7 @@ int vty_client_init(struct osmo_pcap_client *pcap)
install_element(CLIENT_SERVER_NODE, &cfg_tls_log_level_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_client_connect_cmd);
install_element(CLIENT_SERVER_NODE, &cfg_client_disconnect_cmd);
+ install_element(CLIENT_SERVER_NODE, &cfg_client_protocol_cmd);
return 0;
}