summaryrefslogtreecommitdiff
path: root/ctdb/common
diff options
context:
space:
mode:
authorMartin Schwenke <martin@meltin.net>2018-08-17 15:00:31 +1000
committerAmitay Isaacs <amitay@samba.org>2018-08-30 04:48:59 +0200
commite2ac36867d616d06ac37498534ba89eb77f5d833 (patch)
treefe22db9878dfc8cc617a7bb0af71c0858ffc845e /ctdb/common
parent028fdc12e7399dae23fec20deb3ec0284f9d0ce2 (diff)
downloadsamba-e2ac36867d616d06ac37498534ba89eb77f5d833.tar.gz
ctdb-common: Factor out TCP packet parsing code
This can be tested separately. Signed-off-by: Martin Schwenke <martin@meltin.net> Reviewed-by: Amitay Isaacs <amitay@gmail.com>
Diffstat (limited to 'ctdb/common')
-rw-r--r--ctdb/common/system_socket.c296
1 files changed, 149 insertions, 147 deletions
diff --git a/ctdb/common/system_socket.c b/ctdb/common/system_socket.c
index 7adb55040f4..8de70f8bca6 100644
--- a/ctdb/common/system_socket.c
+++ b/ctdb/common/system_socket.c
@@ -736,6 +736,116 @@ int ctdb_sys_send_tcp(const ctdb_sock_addr *dest,
* wscript has checked to make sure that pcap is available if needed.
*/
+static int tcp4_extract(const uint8_t *ip_pkt,
+ size_t pktlen,
+ struct sockaddr_in *src,
+ struct sockaddr_in *dst,
+ uint32_t *ack_seq,
+ uint32_t *seq,
+ int *rst,
+ uint16_t *window)
+{
+ const struct ip *ip;
+ const struct tcphdr *tcp;
+
+ if (pktlen < sizeof(struct ip)) {
+ return EMSGSIZE;
+ }
+
+ /* IP */
+ ip = (const struct ip *)ip_pkt;
+
+ /* We only want IPv4 packets */
+ if (ip->ip_v != 4) {
+ return ENOMSG;
+ }
+ /* Dont look at fragments */
+ if ((ntohs(ip->ip_off)&0x1fff) != 0) {
+ return ENOMSG;
+ }
+ /* we only want TCP */
+ if (ip->ip_p != IPPROTO_TCP) {
+ return ENOMSG;
+ }
+
+ /* make sure its not a short packet */
+ if (offsetof(struct tcphdr, th_ack) + 4 + (ip->ip_hl*4) > pktlen) {
+ return EMSGSIZE;
+ }
+
+ /* TCP */
+ tcp = (const struct tcphdr *)((ip->ip_hl*4) + (const char *)ip);
+
+ /* tell the caller which one we've found */
+ src->sin_family = AF_INET;
+ src->sin_addr.s_addr = ip->ip_src.s_addr;
+ src->sin_port = tcp->th_sport;
+
+ dst->sin_family = AF_INET;
+ dst->sin_addr.s_addr = ip->ip_dst.s_addr;
+ dst->sin_port = tcp->th_dport;
+
+ *ack_seq = tcp->th_ack;
+ *seq = tcp->th_seq;
+ if (window != NULL) {
+ *window = tcp->th_win;
+ }
+ if (rst != NULL) {
+ *rst = tcp->th_flags & TH_RST;
+ }
+
+ return 0;
+}
+
+static int tcp6_extract(const uint8_t *ip_pkt,
+ size_t pktlen,
+ struct sockaddr_in6 *src,
+ struct sockaddr_in6 *dst,
+ uint32_t *ack_seq,
+ uint32_t *seq,
+ int *rst,
+ uint16_t *window)
+{
+ const struct ip6_hdr *ip6;
+ const struct tcphdr *tcp;
+
+ if (pktlen < sizeof(struct ip6_hdr)) {
+ return EMSGSIZE;
+ }
+
+ /* IP6 */
+ ip6 = (const struct ip6_hdr *)ip_pkt;
+
+ /* we only want TCP */
+ if (ip6->ip6_nxt != IPPROTO_TCP) {
+ return ENOMSG;
+ }
+
+ /* TCP */
+ tcp = (const struct tcphdr *)(ip6+1);
+
+ /* tell the caller which one we've found */
+ src->sin6_family = AF_INET6;
+ src->sin6_port = tcp->th_sport;
+ src->sin6_addr = ip6->ip6_src;
+
+ dst->sin6_family = AF_INET6;
+ dst->sin6_port = tcp->th_dport;
+ dst->sin6_addr = ip6->ip6_dst;
+
+ *ack_seq = tcp->th_ack;
+ *seq = tcp->th_seq;
+ if (window != NULL) {
+ *window = tcp->th_win;
+ }
+ if (rst != NULL) {
+ *rst = tcp->th_flags & TH_RST;
+ }
+
+ return 0;
+}
+
+
#ifdef HAVE_AF_PACKET
/*
@@ -792,13 +902,10 @@ int ctdb_sys_read_tcp_packet(int s, void *private_data,
ssize_t nread;
uint8_t pkt[100]; /* Large enough for simple ACK/RST packets */
struct ether_header *eth;
- struct iphdr *ip;
- struct ip6_hdr *ip6;
- struct tcphdr *tcp;
int ret;
nread = recv(s, pkt, sizeof(pkt), MSG_TRUNC);
- if (nread < sizeof(*eth)+sizeof(*ip)) {
+ if (nread < sizeof(*eth)) {
return EMSGSIZE;
}
@@ -810,78 +917,26 @@ int ctdb_sys_read_tcp_packet(int s, void *private_data,
/* we want either IPv4 or IPv6 */
if (ntohs(eth->ether_type) == ETHERTYPE_IP) {
- /* IP */
- ip = (struct iphdr *)(eth+1);
-
- /* We only want IPv4 packets */
- if (ip->version != 4) {
- return ENOMSG;
- }
- /* Dont look at fragments */
- if ((ntohs(ip->frag_off)&0x1fff) != 0) {
- return ENOMSG;
- }
- /* we only want TCP */
- if (ip->protocol != IPPROTO_TCP) {
- return ENOMSG;
- }
-
- /* make sure its not a short packet */
- if (offsetof(struct tcphdr, th_ack) + 4 +
- (ip->ihl*4) + sizeof(*eth) > nread) {
- return EMSGSIZE;
- }
- /* TCP */
- tcp = (struct tcphdr *)((ip->ihl*4) + (char *)ip);
-
- /* tell the caller which one we've found */
- src->ip.sin_family = AF_INET;
- src->ip.sin_addr.s_addr = ip->saddr;
- src->ip.sin_port = tcp->th_sport;
- dst->ip.sin_family = AF_INET;
- dst->ip.sin_addr.s_addr = ip->daddr;
- dst->ip.sin_port = tcp->th_dport;
- *ack_seq = tcp->th_ack;
- *seq = tcp->th_seq;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
+ ret = tcp4_extract(pkt + sizeof(struct ether_header),
+ (size_t)nread - sizeof(struct ether_header),
+ &src->ip,
+ &dst->ip,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
- return 0;
} else if (ntohs(eth->ether_type) == ETHERTYPE_IP6) {
- /* IP6 */
- ip6 = (struct ip6_hdr *)(eth+1);
-
- /* we only want TCP */
- if (ip6->ip6_nxt != IPPROTO_TCP) {
- return ENOMSG;
- }
-
- /* TCP */
- tcp = (struct tcphdr *)(ip6+1);
-
- /* tell the caller which one we've found */
- src->ip6.sin6_family = AF_INET6;
- src->ip6.sin6_port = tcp->th_sport;
- src->ip6.sin6_addr = ip6->ip6_src;
-
- dst->ip6.sin6_family = AF_INET6;
- dst->ip6.sin6_port = tcp->th_dport;
- dst->ip6.sin6_addr = ip6->ip6_dst;
-
- *ack_seq = tcp->th_ack;
- *seq = tcp->th_seq;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
-
- return 0;
+ ret = tcp6_extract(pkt + sizeof(struct ether_header),
+ (size_t)nread - sizeof(struct ether_header),
+ &src->ip6,
+ &dst->ip6,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
}
return ENOMSG;
@@ -923,9 +978,6 @@ int ctdb_sys_read_tcp_packet(int s,
{
int ret;
struct ether_header *eth;
- struct ip *ip;
- struct ip6_hdr *ip6;
- struct tcphdr *tcp;
struct pcap_pkthdr pkthdr;
const u_char *buffer;
pcap_t *pt = (pcap_t *)private_data;
@@ -943,78 +995,28 @@ int ctdb_sys_read_tcp_packet(int s,
/* we want either IPv4 or IPv6 */
if (eth->ether_type == htons(ETHERTYPE_IP)) {
- /* IP */
- ip = (struct ip *)(eth+1);
-
- /* We only want IPv4 packets */
- if (ip->ip_v != 4) {
- return ENOMSG;
- }
- /* Dont look at fragments */
- if ((ntohs(ip->ip_off)&0x1fff) != 0) {
- return ENOMSG;
- }
- /* we only want TCP */
- if (ip->ip_p != IPPROTO_TCP) {
- return ENOMSG;
- }
-
- /* make sure its not a short packet */
- if (offsetof(struct tcphdr, th_ack) + 4 +
- (ip->ip_hl*4) + sizeof(*eth) > pkthdr.caplen) {
- return EMSGSIZE;
- }
- /* TCP */
- tcp = (struct tcphdr *)((ip->ip_hl*4) + (char *)ip);
-
- /* tell the caller which one we've found */
- src->ip.sin_family = AF_INET;
- src->ip.sin_addr.s_addr = ip->ip_src.s_addr;
- src->ip.sin_port = tcp->th_sport;
- dst->ip.sin_family = AF_INET;
- dst->ip.sin_addr.s_addr = ip->ip_dst.s_addr;
- dst->ip.sin_port = tcp->th_dport;
- *ack_seq = tcp->th_ack;
- *seq = tcp->th_seq;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
+ ret = tcp4_extract(buffer + sizeof(struct ether_header),
+ (size_t)(pkthdr.caplen -
+ sizeof(struct ether_header)),
+ &src->ip,
+ &dst->ip,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
- return 0;
} else if (eth->ether_type == htons(ETHERTYPE_IP6)) {
- /* IP6 */
- ip6 = (struct ip6_hdr *)(eth+1);
-
- /* we only want TCP */
- if (ip6->ip6_nxt != IPPROTO_TCP) {
- return ENOMSG;
- }
-
- /* TCP */
- tcp = (struct tcphdr *)(ip6+1);
-
- /* tell the caller which one we've found */
- src->ip6.sin6_family = AF_INET6;
- src->ip6.sin6_port = tcp->th_sport;
- src->ip6.sin6_addr = ip6->ip6_src;
-
- dst->ip6.sin6_family = AF_INET6;
- dst->ip6.sin6_port = tcp->th_dport;
- dst->ip6.sin6_addr = ip6->ip6_dst;
-
- *ack_seq = tcp->th_ack;
- *seq = tcp->th_seq;
- if (window != NULL) {
- *window = tcp->th_win;
- }
- if (rst != NULL) {
- *rst = tcp->th_flags & TH_RST;
- }
-
- return 0;
+ ret = tcp6_extract(buffer + sizeof(struct ether_header),
+ (size_t)(pkthdr.caplen -
+ sizeof(struct ether_header)),
+ &src->ip6,
+ &dst->ip6,
+ ack_seq,
+ seq,
+ rst,
+ window);
+ return ret;
}
return ENOMSG;