1 #define KMSG_COMPONENT "IPVS"
2 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
4 #include <linux/module.h>
5 #include <linux/kernel.h>
8 #include <net/netfilter/nf_conntrack.h>
9 #include <linux/netfilter/nf_conntrack_sip.h>
11 #ifdef CONFIG_IP_VS_DEBUG
12 static const char *ip_vs_dbg_callid(char *buf
, size_t buf_len
,
13 const char *callid
, size_t callid_len
,
16 size_t len
= min(min(callid_len
, (size_t)64), buf_len
- *idx
- 1);
17 memcpy(buf
+ *idx
, callid
, len
);
20 return buf
+ *idx
- len
;
23 #define IP_VS_DEBUG_CALLID(callid, len) \
24 ip_vs_dbg_callid(ip_vs_dbg_buf, sizeof(ip_vs_dbg_buf), \
25 callid, len, &ip_vs_dbg_idx)
28 static int get_callid(const char *dptr
, unsigned int dataoff
,
30 unsigned int *matchoff
, unsigned int *matchlen
)
34 int ret
= ct_sip_get_header(NULL
, dptr
, dataoff
, datalen
,
35 SIP_HDR_CALL_ID
, matchoff
,
44 /* Empty callid is useless */
48 /* Too large is useless */
49 if (*matchlen
> IP_VS_PEDATA_MAXLEN
)
52 /* SIP headers are always followed by a line terminator */
53 if (*matchoff
+ *matchlen
== datalen
)
56 /* RFC 2543 allows lines to be terminated with CR, LF or CRLF,
57 * RFC 3261 allows only CRLF, we support both. */
58 if (*(dptr
+ *matchoff
+ *matchlen
) != '\r' &&
59 *(dptr
+ *matchoff
+ *matchlen
) != '\n')
62 IP_VS_DBG_BUF(9, "SIP callid %s (%d bytes)\n",
63 IP_VS_DEBUG_CALLID(dptr
+ *matchoff
, *matchlen
),
69 ip_vs_sip_fill_param(struct ip_vs_conn_param
*p
, struct sk_buff
*skb
)
71 struct ip_vs_iphdr iph
;
72 unsigned int dataoff
, datalen
, matchoff
, matchlen
;
75 ip_vs_fill_iphdr(p
->af
, skb_network_header(skb
), &iph
);
77 /* Only useful with UDP */
78 if (iph
.protocol
!= IPPROTO_UDP
)
82 dataoff
= iph
.len
+ sizeof(struct udphdr
);
83 if (dataoff
>= skb
->len
)
86 dptr
= skb
->data
+ dataoff
;
87 datalen
= skb
->len
- dataoff
;
89 if (get_callid(dptr
, dataoff
, datalen
, &matchoff
, &matchlen
))
92 p
->pe_data
= kmalloc(matchlen
, GFP_ATOMIC
);
96 /* N.B: pe_data is only set on success,
97 * this allows fallback to the default persistence logic on failure
99 memcpy(p
->pe_data
, dptr
+ matchoff
, matchlen
);
100 p
->pe_data_len
= matchlen
;
105 static bool ip_vs_sip_ct_match(const struct ip_vs_conn_param
*p
,
106 struct ip_vs_conn
*ct
)
111 if (ct
->af
== p
->af
&&
112 ip_vs_addr_equal(p
->af
, p
->caddr
, &ct
->caddr
) &&
113 /* protocol should only be IPPROTO_IP if
114 * d_addr is a fwmark */
115 ip_vs_addr_equal(p
->protocol
== IPPROTO_IP
? AF_UNSPEC
: p
->af
,
116 p
->vaddr
, &ct
->vaddr
) &&
117 ct
->vport
== p
->vport
&&
118 ct
->flags
& IP_VS_CONN_F_TEMPLATE
&&
119 ct
->protocol
== p
->protocol
&&
120 ct
->pe_data
&& ct
->pe_data_len
== p
->pe_data_len
&&
121 !memcmp(ct
->pe_data
, p
->pe_data
, p
->pe_data_len
))
124 IP_VS_DBG_BUF(9, "SIP template match %s %s->%s:%d %s\n",
125 ip_vs_proto_name(p
->protocol
),
126 IP_VS_DEBUG_CALLID(p
->pe_data
, p
->pe_data_len
),
127 IP_VS_DBG_ADDR(p
->af
, p
->vaddr
), ntohs(p
->vport
),
128 ret
? "hit" : "not hit");
133 static u32
ip_vs_sip_hashkey_raw(const struct ip_vs_conn_param
*p
,
134 u32 initval
, bool inverse
)
136 return jhash(p
->pe_data
, p
->pe_data_len
, initval
);
139 static int ip_vs_sip_show_pe_data(const struct ip_vs_conn
*cp
, char *buf
)
141 memcpy(buf
, cp
->pe_data
, cp
->pe_data_len
);
142 return cp
->pe_data_len
;
145 static struct ip_vs_pe ip_vs_sip_pe
=
148 .refcnt
= ATOMIC_INIT(0),
149 .module
= THIS_MODULE
,
150 .n_list
= LIST_HEAD_INIT(ip_vs_sip_pe
.n_list
),
151 .fill_param
= ip_vs_sip_fill_param
,
152 .ct_match
= ip_vs_sip_ct_match
,
153 .hashkey_raw
= ip_vs_sip_hashkey_raw
,
154 .show_pe_data
= ip_vs_sip_show_pe_data
,
157 static int __init
ip_vs_sip_init(void)
159 return register_ip_vs_pe(&ip_vs_sip_pe
);
162 static void __exit
ip_vs_sip_cleanup(void)
164 unregister_ip_vs_pe(&ip_vs_sip_pe
);
167 module_init(ip_vs_sip_init
);
168 module_exit(ip_vs_sip_cleanup
);
169 MODULE_LICENSE("GPL");