📄 ip_conntrack_proto_sctp.c
字号:
/* * Connection tracking protocol helper module for SCTP. * * SCTP is defined in RFC 2960. References to various sections in this code * are to this RFC. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. *//* * Added support for proc manipulation of timeouts. */#include <linux/types.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/netfilter.h>#include <linux/module.h>#include <linux/in.h>#include <linux/ip.h>#include <linux/sctp.h>#include <linux/string.h>#include <linux/seq_file.h>#include <linux/netfilter_ipv4/ip_conntrack.h>#include <linux/netfilter_ipv4/ip_conntrack_protocol.h>#if 0#define DEBUGP(format, ...) printk(format, ## __VA_ARGS__)#else#define DEBUGP(format, args...)#endif/* Protects conntrack->proto.sctp */static DEFINE_RWLOCK(sctp_lock);/* FIXME: Examine ipfilter's timeouts and conntrack transitions more closely. They're more complex. --RR And so for me for SCTP :D -Kiran */static const char *sctp_conntrack_names[] = { "NONE", "CLOSED", "COOKIE_WAIT", "COOKIE_ECHOED", "ESTABLISHED", "SHUTDOWN_SENT", "SHUTDOWN_RECD", "SHUTDOWN_ACK_SENT",};#define SECS * HZ#define MINS * 60 SECS#define HOURS * 60 MINS#define DAYS * 24 HOURSstatic unsigned long ip_ct_sctp_timeout_closed = 10 SECS;static unsigned long ip_ct_sctp_timeout_cookie_wait = 3 SECS;static unsigned long ip_ct_sctp_timeout_cookie_echoed = 3 SECS;static unsigned long ip_ct_sctp_timeout_established = 5 DAYS;static unsigned long ip_ct_sctp_timeout_shutdown_sent = 300 SECS / 1000;static unsigned long ip_ct_sctp_timeout_shutdown_recd = 300 SECS / 1000;static unsigned long ip_ct_sctp_timeout_shutdown_ack_sent = 3 SECS;static const unsigned long * sctp_timeouts[]= { NULL, /* SCTP_CONNTRACK_NONE */ &ip_ct_sctp_timeout_closed, /* SCTP_CONNTRACK_CLOSED */ &ip_ct_sctp_timeout_cookie_wait, /* SCTP_CONNTRACK_COOKIE_WAIT */ &ip_ct_sctp_timeout_cookie_echoed, /* SCTP_CONNTRACK_COOKIE_ECHOED */ &ip_ct_sctp_timeout_established, /* SCTP_CONNTRACK_ESTABLISHED */ &ip_ct_sctp_timeout_shutdown_sent, /* SCTP_CONNTRACK_SHUTDOWN_SENT */ &ip_ct_sctp_timeout_shutdown_recd, /* SCTP_CONNTRACK_SHUTDOWN_RECD */ &ip_ct_sctp_timeout_shutdown_ack_sent /* SCTP_CONNTRACK_SHUTDOWN_ACK_SENT */ };#define sNO SCTP_CONNTRACK_NONE#define sCL SCTP_CONNTRACK_CLOSED#define sCW SCTP_CONNTRACK_COOKIE_WAIT#define sCE SCTP_CONNTRACK_COOKIE_ECHOED#define sES SCTP_CONNTRACK_ESTABLISHED#define sSS SCTP_CONNTRACK_SHUTDOWN_SENT#define sSR SCTP_CONNTRACK_SHUTDOWN_RECD#define sSA SCTP_CONNTRACK_SHUTDOWN_ACK_SENT#define sIV SCTP_CONNTRACK_MAX/* These are the descriptions of the states:NOTE: These state names are tantalizingly similar to the states of an SCTP endpoint. But the interpretation of the states is a little different,considering that these are the states of the connection and not of an end point. Please note the subtleties. -KiranNONE - Nothing so far.COOKIE WAIT - We have seen an INIT chunk in the original direction, or also an INIT_ACK chunk in the reply direction.COOKIE ECHOED - We have seen a COOKIE_ECHO chunk in the original direction.ESTABLISHED - We have seen a COOKIE_ACK in the reply direction.SHUTDOWN_SENT - We have seen a SHUTDOWN chunk in the original direction.SHUTDOWN_RECD - We have seen a SHUTDOWN chunk in the reply directoin.SHUTDOWN_ACK_SENT - We have seen a SHUTDOWN_ACK chunk in the direction opposite to that of the SHUTDOWN chunk.CLOSED - We have seen a SHUTDOWN_COMPLETE chunk in the direction of the SHUTDOWN chunk. Connection is closed.*//* TODO - I have assumed that the first INIT is in the original direction. This messes things when an INIT comes in the reply direction in CLOSED state. - Check the error type in the reply dir before transitioning from cookie echoed to closed. - Sec 5.2.4 of RFC 2960 - Multi Homing support.*//* SCTP conntrack state transitions */static const enum sctp_conntrack sctp_conntracks[2][9][SCTP_CONNTRACK_MAX] = { {/* ORIGINAL *//* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA *//* init */ {sCW, sCW, sCW, sCE, sES, sSS, sSR, sSA},/* init_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* abort */ {sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL},/* shutdown */ {sCL, sCL, sCW, sCE, sSS, sSS, sSR, sSA},/* shutdown_ack */ {sSA, sCL, sCW, sCE, sES, sSA, sSA, sSA},/* error */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant have Stale cookie*//* cookie_echo */ {sCL, sCL, sCE, sCE, sES, sSS, sSR, sSA},/* 5.2.4 - Big TODO *//* cookie_ack */ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in orig dir *//* shutdown_comp*/ {sCL, sCL, sCW, sCE, sES, sSS, sSR, sCL} }, {/* REPLY *//* sNO, sCL, sCW, sCE, sES, sSS, sSR, sSA *//* init */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* INIT in sCL Big TODO *//* init_ack */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* abort */ {sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL},/* shutdown */ {sIV, sCL, sCW, sCE, sSR, sSS, sSR, sSA},/* shutdown_ack */ {sIV, sCL, sCW, sCE, sES, sSA, sSA, sSA},/* error */ {sIV, sCL, sCW, sCL, sES, sSS, sSR, sSA},/* cookie_echo */ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sSA},/* Cant come in reply dir *//* cookie_ack */ {sIV, sCL, sCW, sES, sES, sSS, sSR, sSA},/* shutdown_comp*/ {sIV, sCL, sCW, sCE, sES, sSS, sSR, sCL} }};static int sctp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, struct ip_conntrack_tuple *tuple){ sctp_sctphdr_t _hdr, *hp; DEBUGP(__FUNCTION__); DEBUGP("\n"); /* Actually only need first 8 bytes. */ hp = skb_header_pointer(skb, dataoff, 8, &_hdr); if (hp == NULL) return 0; tuple->src.u.sctp.port = hp->source; tuple->dst.u.sctp.port = hp->dest; return 1;}static int sctp_invert_tuple(struct ip_conntrack_tuple *tuple, const struct ip_conntrack_tuple *orig){ DEBUGP(__FUNCTION__); DEBUGP("\n"); tuple->src.u.sctp.port = orig->dst.u.sctp.port; tuple->dst.u.sctp.port = orig->src.u.sctp.port; return 1;}/* Print out the per-protocol part of the tuple. */static int sctp_print_tuple(struct seq_file *s, const struct ip_conntrack_tuple *tuple){ DEBUGP(__FUNCTION__); DEBUGP("\n"); return seq_printf(s, "sport=%hu dport=%hu ", ntohs(tuple->src.u.sctp.port), ntohs(tuple->dst.u.sctp.port));}/* Print out the private part of the conntrack. */static int sctp_print_conntrack(struct seq_file *s, const struct ip_conntrack *conntrack){ enum sctp_conntrack state; DEBUGP(__FUNCTION__); DEBUGP("\n"); read_lock_bh(&sctp_lock); state = conntrack->proto.sctp.state; read_unlock_bh(&sctp_lock); return seq_printf(s, "%s ", sctp_conntrack_names[state]);}#define for_each_sctp_chunk(skb, sch, _sch, offset, count) \for (offset = skb->nh.iph->ihl * 4 + sizeof(sctp_sctphdr_t), count = 0; \ offset < skb->len && \ (sch = skb_header_pointer(skb, offset, sizeof(_sch), &_sch)); \ offset += (htons(sch->length) + 3) & ~3, count++)/* Some validity checks to make sure the chunks are fine */static int do_basic_checks(struct ip_conntrack *conntrack, const struct sk_buff *skb, char *map){ u_int32_t offset, count; sctp_chunkhdr_t _sch, *sch; int flag; DEBUGP(__FUNCTION__); DEBUGP("\n"); flag = 0; for_each_sctp_chunk (skb, sch, _sch, offset, count) { DEBUGP("Chunk Num: %d Type: %d\n", count, sch->type); if (sch->type == SCTP_CID_INIT || sch->type == SCTP_CID_INIT_ACK || sch->type == SCTP_CID_SHUTDOWN_COMPLETE) { flag = 1; } /* Cookie Ack/Echo chunks not the first OR Init / Init Ack / Shutdown compl chunks not the only chunks */ if ((sch->type == SCTP_CID_COOKIE_ACK || sch->type == SCTP_CID_COOKIE_ECHO || flag) && count !=0 ) { DEBUGP("Basic checks failed\n"); return 1; } if (map) { set_bit(sch->type, (void *)map); } } DEBUGP("Basic checks passed\n"); return 0;}static int new_state(enum ip_conntrack_dir dir, enum sctp_conntrack cur_state, int chunk_type){ int i; DEBUGP(__FUNCTION__); DEBUGP("\n"); DEBUGP("Chunk type: %d\n", chunk_type); switch (chunk_type) { case SCTP_CID_INIT: DEBUGP("SCTP_CID_INIT\n"); i = 0; break; case SCTP_CID_INIT_ACK: DEBUGP("SCTP_CID_INIT_ACK\n"); i = 1; break; case SCTP_CID_ABORT: DEBUGP("SCTP_CID_ABORT\n"); i = 2; break; case SCTP_CID_SHUTDOWN: DEBUGP("SCTP_CID_SHUTDOWN\n"); i = 3; break; case SCTP_CID_SHUTDOWN_ACK: DEBUGP("SCTP_CID_SHUTDOWN_ACK\n"); i = 4; break; case SCTP_CID_ERROR: DEBUGP("SCTP_CID_ERROR\n"); i = 5; break; case SCTP_CID_COOKIE_ECHO: DEBUGP("SCTP_CID_COOKIE_ECHO\n"); i = 6; break; case SCTP_CID_COOKIE_ACK: DEBUGP("SCTP_CID_COOKIE_ACK\n"); i = 7; break; case SCTP_CID_SHUTDOWN_COMPLETE: DEBUGP("SCTP_CID_SHUTDOWN_COMPLETE\n"); i = 8; break; default: /* Other chunks like DATA, SACK, HEARTBEAT and its ACK do not cause a change in state */ DEBUGP("Unknown chunk type, Will stay in %s\n", sctp_conntrack_names[cur_state]); return cur_state; } DEBUGP("dir: %d cur_state: %s chunk_type: %d new_state: %s\n", dir, sctp_conntrack_names[cur_state], chunk_type, sctp_conntrack_names[sctp_conntracks[dir][i][cur_state]]); return sctp_conntracks[dir][i][cur_state];}/* Returns verdict for packet, or -1 for invalid. */static int sctp_packet(struct ip_conntrack *conntrack, const struct sk_buff *skb, enum ip_conntrack_info ctinfo){ enum sctp_conntrack newconntrack, oldsctpstate; struct iphdr *iph = skb->nh.iph; sctp_sctphdr_t _sctph, *sh; sctp_chunkhdr_t _sch, *sch; u_int32_t offset, count; char map[256 / sizeof (char)] = {0}; DEBUGP(__FUNCTION__); DEBUGP("\n"); sh = skb_header_pointer(skb, iph->ihl * 4, sizeof(_sctph), &_sctph); if (sh == NULL) return -1; if (do_basic_checks(conntrack, skb, map) != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -