Add support for generating IPIP to osmo-pcap-client

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
This commit is contained in:
Harald Welte 2017-07-21 18:12:01 +02:00
parent 5f071cd2c6
commit abc6dd83bc
3 changed files with 121 additions and 17 deletions

View File

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

View File

@ -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;
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->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);
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]);
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)

View File

@ -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;
}