diff options
-rw-r--r-- | include/linux/netfilter/nf_conntrack_sip.h | 5 | ||||
-rw-r--r-- | net/ipv4/netfilter/nf_nat_sip.c | 46 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_sip.c | 64 |
3 files changed, 77 insertions, 38 deletions
diff --git a/include/linux/netfilter/nf_conntrack_sip.h b/include/linux/netfilter/nf_conntrack_sip.h index 9131cbc9b9de..480b26f40ce4 100644 --- a/include/linux/netfilter/nf_conntrack_sip.h +++ b/include/linux/netfilter/nf_conntrack_sip.h | |||
@@ -6,8 +6,6 @@ | |||
6 | #define SIP_TIMEOUT 3600 | 6 | #define SIP_TIMEOUT 3600 |
7 | 7 | ||
8 | enum sip_header_pos { | 8 | enum sip_header_pos { |
9 | POS_REG_REQ_URI, | ||
10 | POS_REQ_URI, | ||
11 | POS_FROM, | 9 | POS_FROM, |
12 | POS_TO, | 10 | POS_TO, |
13 | POS_VIA, | 11 | POS_VIA, |
@@ -59,6 +57,9 @@ extern unsigned int (*nf_nat_sdp_hook)(struct sk_buff *skb, | |||
59 | unsigned int *datalen, | 57 | unsigned int *datalen, |
60 | struct nf_conntrack_expect *exp); | 58 | struct nf_conntrack_expect *exp); |
61 | 59 | ||
60 | extern int ct_sip_parse_request(const struct nf_conn *ct, | ||
61 | const char *dptr, unsigned int datalen, | ||
62 | unsigned int *matchoff, unsigned int *matchlen); | ||
62 | extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, | 63 | extern int ct_sip_get_info(const struct nf_conn *ct, const char *dptr, |
63 | size_t dlen, unsigned int *matchoff, | 64 | size_t dlen, unsigned int *matchoff, |
64 | unsigned int *matchlen, enum sip_header_pos pos); | 65 | unsigned int *matchlen, enum sip_header_pos pos); |
diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index aa8a4f492baf..60151b5901a5 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c | |||
@@ -78,20 +78,17 @@ static unsigned int mangle_packet(struct sk_buff *skb, | |||
78 | return 1; | 78 | return 1; |
79 | } | 79 | } |
80 | 80 | ||
81 | static int map_sip_addr(struct sk_buff *skb, | 81 | static int map_addr(struct sk_buff *skb, |
82 | const char **dptr, unsigned int *datalen, | 82 | const char **dptr, unsigned int *datalen, |
83 | enum sip_header_pos pos, struct addr_map *map) | 83 | unsigned int matchoff, unsigned int matchlen, |
84 | struct addr_map *map) | ||
84 | { | 85 | { |
85 | enum ip_conntrack_info ctinfo; | 86 | enum ip_conntrack_info ctinfo; |
86 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 87 | struct nf_conn *ct __maybe_unused = nf_ct_get(skb, &ctinfo); |
87 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); | 88 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
88 | unsigned int matchlen, matchoff, addrlen; | 89 | unsigned int addrlen; |
89 | char *addr; | 90 | char *addr; |
90 | 91 | ||
91 | if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, | ||
92 | pos) <= 0) | ||
93 | return 1; | ||
94 | |||
95 | if ((matchlen == map->addr[dir].srciplen || | 92 | if ((matchlen == map->addr[dir].srciplen || |
96 | matchlen == map->addr[dir].srclen) && | 93 | matchlen == map->addr[dir].srclen) && |
97 | strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { | 94 | strncmp(*dptr + matchoff, map->addr[dir].src, matchlen) == 0) { |
@@ -109,13 +106,27 @@ static int map_sip_addr(struct sk_buff *skb, | |||
109 | addr, addrlen); | 106 | addr, addrlen); |
110 | } | 107 | } |
111 | 108 | ||
109 | static int map_sip_addr(struct sk_buff *skb, | ||
110 | const char **dptr, unsigned int *datalen, | ||
111 | enum sip_header_pos pos, struct addr_map *map) | ||
112 | { | ||
113 | enum ip_conntrack_info ctinfo; | ||
114 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | ||
115 | unsigned int matchlen, matchoff; | ||
116 | |||
117 | if (ct_sip_get_info(ct, *dptr, *datalen, &matchoff, &matchlen, | ||
118 | pos) <= 0) | ||
119 | return 1; | ||
120 | return map_addr(skb, dptr, datalen, matchoff, matchlen, map); | ||
121 | } | ||
122 | |||
112 | static unsigned int ip_nat_sip(struct sk_buff *skb, | 123 | static unsigned int ip_nat_sip(struct sk_buff *skb, |
113 | const char **dptr, unsigned int *datalen) | 124 | const char **dptr, unsigned int *datalen) |
114 | { | 125 | { |
115 | enum ip_conntrack_info ctinfo; | 126 | enum ip_conntrack_info ctinfo; |
116 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); | 127 | struct nf_conn *ct = nf_ct_get(skb, &ctinfo); |
117 | enum sip_header_pos pos; | ||
118 | struct addr_map map; | 128 | struct addr_map map; |
129 | unsigned int matchoff, matchlen; | ||
119 | 130 | ||
120 | if (*datalen < strlen("SIP/2.0")) | 131 | if (*datalen < strlen("SIP/2.0")) |
121 | return NF_ACCEPT; | 132 | return NF_ACCEPT; |
@@ -124,18 +135,9 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, | |||
124 | 135 | ||
125 | /* Basic rules: requests and responses. */ | 136 | /* Basic rules: requests and responses. */ |
126 | if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { | 137 | if (strnicmp(*dptr, "SIP/2.0", strlen("SIP/2.0")) != 0) { |
127 | /* 10.2: Constructing the REGISTER Request: | 138 | if (ct_sip_parse_request(ct, *dptr, *datalen, |
128 | * | 139 | &matchoff, &matchlen) > 0 && |
129 | * The "userinfo" and "@" components of the SIP URI MUST NOT | 140 | !map_addr(skb, dptr, datalen, matchoff, matchlen, &map)) |
130 | * be present. | ||
131 | */ | ||
132 | if (*datalen >= strlen("REGISTER") && | ||
133 | strnicmp(*dptr, "REGISTER", strlen("REGISTER")) == 0) | ||
134 | pos = POS_REG_REQ_URI; | ||
135 | else | ||
136 | pos = POS_REQ_URI; | ||
137 | |||
138 | if (!map_sip_addr(skb, dptr, datalen, pos, &map)) | ||
139 | return NF_DROP; | 141 | return NF_DROP; |
140 | } | 142 | } |
141 | 143 | ||
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 801fcb3c749f..bb4396155681 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c | |||
@@ -65,20 +65,6 @@ struct sip_header_nfo { | |||
65 | }; | 65 | }; |
66 | 66 | ||
67 | static const struct sip_header_nfo ct_sip_hdrs[] = { | 67 | static const struct sip_header_nfo ct_sip_hdrs[] = { |
68 | [POS_REG_REQ_URI] = { /* SIP REGISTER request URI */ | ||
69 | .lname = "sip:", | ||
70 | .lnlen = sizeof("sip:") - 1, | ||
71 | .ln_str = ":", | ||
72 | .ln_strlen = sizeof(":") - 1, | ||
73 | .match_len = epaddr_len, | ||
74 | }, | ||
75 | [POS_REQ_URI] = { /* SIP request URI */ | ||
76 | .lname = "sip:", | ||
77 | .lnlen = sizeof("sip:") - 1, | ||
78 | .ln_str = "@", | ||
79 | .ln_strlen = sizeof("@") - 1, | ||
80 | .match_len = epaddr_len, | ||
81 | }, | ||
82 | [POS_FROM] = { /* SIP From header */ | 68 | [POS_FROM] = { /* SIP From header */ |
83 | .lname = "From:", | 69 | .lname = "From:", |
84 | .lnlen = sizeof("From:") - 1, | 70 | .lnlen = sizeof("From:") - 1, |
@@ -164,6 +150,18 @@ const char *ct_sip_search(const char *needle, const char *haystack, | |||
164 | } | 150 | } |
165 | EXPORT_SYMBOL_GPL(ct_sip_search); | 151 | EXPORT_SYMBOL_GPL(ct_sip_search); |
166 | 152 | ||
153 | static int string_len(const struct nf_conn *ct, const char *dptr, | ||
154 | const char *limit, int *shift) | ||
155 | { | ||
156 | int len = 0; | ||
157 | |||
158 | while (dptr < limit && isalpha(*dptr)) { | ||
159 | dptr++; | ||
160 | len++; | ||
161 | } | ||
162 | return len; | ||
163 | } | ||
164 | |||
167 | static int digits_len(const struct nf_conn *ct, const char *dptr, | 165 | static int digits_len(const struct nf_conn *ct, const char *dptr, |
168 | const char *limit, int *shift) | 166 | const char *limit, int *shift) |
169 | { | 167 | { |
@@ -258,6 +256,44 @@ static int skp_epaddr_len(const struct nf_conn *ct, const char *dptr, | |||
258 | return epaddr_len(ct, dptr, limit, shift); | 256 | return epaddr_len(ct, dptr, limit, shift); |
259 | } | 257 | } |
260 | 258 | ||
259 | /* Parse a SIP request line of the form: | ||
260 | * | ||
261 | * Request-Line = Method SP Request-URI SP SIP-Version CRLF | ||
262 | * | ||
263 | * and return the offset and length of the address contained in the Request-URI. | ||
264 | */ | ||
265 | int ct_sip_parse_request(const struct nf_conn *ct, | ||
266 | const char *dptr, unsigned int datalen, | ||
267 | unsigned int *matchoff, unsigned int *matchlen) | ||
268 | { | ||
269 | const char *start = dptr, *limit = dptr + datalen; | ||
270 | unsigned int mlen; | ||
271 | int shift = 0; | ||
272 | |||
273 | /* Skip method and following whitespace */ | ||
274 | mlen = string_len(ct, dptr, limit, NULL); | ||
275 | if (!mlen) | ||
276 | return 0; | ||
277 | dptr += mlen; | ||
278 | if (++dptr >= limit) | ||
279 | return 0; | ||
280 | |||
281 | /* Find SIP URI */ | ||
282 | limit -= strlen("sip:"); | ||
283 | for (; dptr < limit; dptr++) { | ||
284 | if (*dptr == '\r' || *dptr == '\n') | ||
285 | return -1; | ||
286 | if (strnicmp(dptr, "sip:", strlen("sip:")) == 0) | ||
287 | break; | ||
288 | } | ||
289 | *matchlen = skp_epaddr_len(ct, dptr, limit, &shift); | ||
290 | if (!*matchlen) | ||
291 | return 0; | ||
292 | *matchoff = dptr - start + shift; | ||
293 | return 1; | ||
294 | } | ||
295 | EXPORT_SYMBOL_GPL(ct_sip_parse_request); | ||
296 | |||
261 | /* Returns 0 if not found, -1 error parsing. */ | 297 | /* Returns 0 if not found, -1 error parsing. */ |
262 | int ct_sip_get_info(const struct nf_conn *ct, | 298 | int ct_sip_get_info(const struct nf_conn *ct, |
263 | const char *dptr, size_t dlen, | 299 | const char *dptr, size_t dlen, |