Navigation


source: freeDiameter/extensions/app_redirect/ard_rules.c @ 738:d666051658bd

Last change on this file since 738:d666051658bd was 738:d666051658bd, checked in by Sebastien Decugis <sdecugis@nict.go.jp>, 11 years ago

Fix broken 'almostcasecmp' logic

File size: 9.5 KB
Line 
1/*********************************************************************************************************
2* Software License Agreement (BSD License)                                                               *
3* Author: Sebastien Decugis <sdecugis@nict.go.jp>                                                        *
4*                                                                                                        *
5* Copyright (c) 2011, WIDE Project and NICT                                                              *
6* All rights reserved.                                                                                   *
7*                                                                                                        *
8* Redistribution and use of this software in source and binary forms, with or without modification, are  *
9* permitted provided that the following conditions are met:                                              *
10*                                                                                                        *
11* * Redistributions of source code must retain the above                                                 *
12*   copyright notice, this list of conditions and the                                                    *
13*   following disclaimer.                                                                                *
14*                                                                                                        *
15* * Redistributions in binary form must reproduce the above                                              *
16*   copyright notice, this list of conditions and the                                                    *
17*   following disclaimer in the documentation and/or other                                               *
18*   materials provided with the distribution.                                                            *
19*                                                                                                        *
20* * Neither the name of the WIDE Project or NICT nor the                                                 *
21*   names of its contributors may be used to endorse or                                                  *
22*   promote products derived from this software without                                                  *
23*   specific prior written permission of WIDE Project and                                                *
24*   NICT.                                                                                                *
25*                                                                                                        *
26* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED *
27* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
28* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR *
29* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT     *
30* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS    *
31* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR *
32* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF   *
33* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                             *
34*********************************************************************************************************/
35
36#include "app_redir.h"
37
38static const char * redir_type_str[] = {
39        "DONT_CACHE",
40        "ALL_SESSION",
41        "ALL_REALM",
42        "REALM_AND_APPLICATION",
43        "ALL_APPLICATION",
44        "ALL_HOST",
45        "ALL_USER"
46};
47
48struct dict_object * avp_Redirect_Host = NULL;
49struct dict_object * avp_Redirect_Host_Usage = NULL;
50struct dict_object * avp_Redirect_Max_Cache_Time = NULL;
51       
52
53void ard_rule_dump(struct ard_rule * r)
54{
55        struct fd_list * li;
56        fd_log_debug("   rule @%p: %s, %us\n", r, redir_type_str[r->type], r->rct);
57        for (li = r->criteria.next; li != &r->criteria; li = li->next) {
58                struct ard_criteria * c = li->o;
59                fd_log_debug("      Criteria: ");
60                switch (c->type) {
61                        case FROM_ID:
62                                fd_log_debug("received from peer %s'%s'", c->is_regex?"REGEX":"", c->s);
63                                break;
64                        case FROM_REALM:
65                                fd_log_debug("received from realm %s'%s'", c->is_regex?"REGEX":"", c->s);
66                                break;
67                        case APP_ID:
68                                fd_log_debug("application id is %u", c->i);
69                                break;
70                        case AVP_INT:
71                                fd_log_debug("contains '%s' AVP with value '%d'", c->avp_info.avp_name, c->i);
72                                break;
73                        case AVP_STR:
74                                fd_log_debug("contains '%s' AVP with value %s'%s'", c->avp_info.avp_name, c->is_regex?"REGEX":"", c->s);
75                                break;
76               
77                        default:
78                                fd_log_debug("invalid (%d)!", c->type);
79                }
80                fd_log_debug("\n");
81        }
82        for (li = r->targets.next; li != &r->targets; li = li->next) {
83                struct ard_target * t = li->o;
84                fd_log_debug("      Redirect to: '%s'\n", t->s);
85        }
86}
87
88/* Tells if the string in s (is0term or not) matches the string in the criteria (regex or not) */
89static int str_match(struct ard_criteria * c, uint8_t *s, size_t l, int is0term, int * match)
90{
91        TRACE_ENTRY("%p %p %zd %d %p", c, s, l, is0term, match);
92       
93        *match = 0;
94       
95        if (c->is_regex == 0) {
96                if ( ! fd_os_almostcasesrch(c->s, c->sl, s, l, NULL) )
97                        *match = 1;
98        } else {
99                int err;
100#ifdef HAVE_REG_STARTEND
101                regmatch_t pmatch[1];
102                memset(pmatch, 0, sizeof(pmatch));
103                pmatch[0].rm_so = 0;
104                pmatch[0].rm_eo = l;
105                err = regexec(&c->preg, (char *)s, 0, pmatch, REG_STARTEND);
106#else /* HAVE_REG_STARTEND */
107                if (!is0term) {
108                        /* We have to create a copy of the string in this case */
109                        char *mystrcpy;
110                        CHECK_MALLOC( mystrcpy = (char *)os0dup(s, l) );
111                        err = regexec(&c->preg, mystrcpy, 0, NULL, 0);
112                        free(mystrcpy);
113                } else {
114                        err = regexec(&c->preg, (char *)s, 0, NULL, 0);
115                }
116#endif /* HAVE_REG_STARTEND */
117               
118                /* Now check the result */
119                if (err == 0) {
120                        /* We have a match */
121                        *match = 1;
122                } else if (err != REG_NOMATCH) {
123                        /* An error occurred */
124                        char * buf;
125                        size_t bl;
126
127                        /* Error while compiling the regex */
128                        TRACE_DEBUG(INFO, "Error while executing the regular expression '%s':", c->s);
129
130                        /* Get the error message size */
131                        bl = regerror(err, &c->preg, NULL, 0);
132
133                        /* Alloc the buffer for error message */
134                        CHECK_MALLOC( buf = malloc(bl) );
135
136                        /* Get the error message content */
137                        regerror(err, &c->preg, buf, bl);
138                        TRACE_DEBUG(INFO, "\t%s", buf);
139
140                        /* Free the buffer, return the error */
141                        free(buf);
142                        return (err == REG_ESPACE) ? ENOMEM : EINVAL;
143                }
144        }
145        return 0;
146}
147
148/* Search the first matching rule in the config */
149static int find_rule(struct msg * msg, struct ard_rule ** found)
150{
151        struct fd_list * li;
152        struct msg_hdr * mhdr = NULL;
153        struct peer_hdr * phdr = NULL;
154       
155        ASSERT(msg && found);
156        *found = NULL;
157       
158        /* Get the message's header */
159        CHECK_FCT( fd_msg_hdr(msg, &mhdr) );
160       
161        /* Get the message's origin */
162        {
163                DiamId_t id;
164                size_t len;
165                CHECK_FCT( fd_msg_source_get(msg, &id, &len) );
166                CHECK_FCT( fd_peer_getbyid(id, len, 0, &phdr) );
167        }
168       
169        /* Now for each rule check if all criteria match */
170        for (li = ard_conf->rules.next; li != &ard_conf->rules; li = li->next) {
171                struct fd_list * lic;
172                struct ard_rule * r = li->o;
173                int is_match = 1;
174               
175                for (lic = r->criteria.next; is_match && (lic != &r->criteria); lic = lic->next) {
176                        struct ard_criteria * c = lic->o;
177                       
178                        /* Does this criteria match ? */
179                        switch (c->type) {
180                                case APP_ID:
181                                        if (c->i != mhdr->msg_appl)
182                                                is_match = 0;
183                                        break;
184                                       
185                                case FROM_ID:
186                                        CHECK_FCT( str_match(c, (uint8_t *)phdr->info.pi_diamid, phdr->info.pi_diamidlen, 1, &is_match) );
187                                        break;
188                               
189                                case FROM_REALM:
190                                        if (phdr->info.runtime.pir_realm) {
191                                                CHECK_FCT( str_match(c, (uint8_t *)phdr->info.runtime.pir_realm, phdr->info.runtime.pir_realmlen, 1, &is_match) );
192                                        } else {
193                                                /* since we don't have the realm it was received from, assume it does not match */
194                                                TRACE_DEBUG(INFO, "Missing realm info for peer '%s', skipping rule %p", phdr->info.pi_diamid, r);
195                                                is_match = 0;
196                                        }
197                                        break;
198                               
199                                case AVP_INT:
200                                case AVP_STR:
201                                        /* We have to search the whole message for the matching AVP */
202                                        {
203                                                is_match = 0;
204                                                struct avp * avp = NULL;
205                                                CHECK_FCT(  fd_msg_browse(msg, MSG_BRW_FIRST_CHILD, &avp, NULL)  );
206                                                while (avp && !is_match) {
207                                                        struct avp_hdr * ahdr = NULL;
208                                                        CHECK_FCT( fd_msg_avp_hdr(avp, &ahdr) );
209
210                                                        if ( (ahdr->avp_code == c->avp_info.avp_code)
211                                                          && (ahdr->avp_vendor == c->avp_info.avp_vendor) )  /* always 0 if no V flag */
212                                                        {
213                                                                /* dict-parse this AVP to ensure it has a value */
214                                                                CHECK_FCT( fd_msg_parse_dict( avp, fd_g_config->cnf_dict, NULL ) );
215
216                                                                /* Now check if the value matches our criteria */
217                                                                if (c->type == AVP_INT) {
218                                                                        if (ahdr->avp_value->u32 == c->i)
219                                                                                is_match = 1;
220                                                                } else {
221                                                                        /* it is AVP_STR */
222                                                                        CHECK_FCT( str_match(c, ahdr->avp_value->os.data, ahdr->avp_value->os.len, 0, &is_match) );
223                                                                }
224
225                                                                if (is_match)
226                                                                        break;
227                                                        }
228
229                                                        /* go to next */
230                                                        CHECK_FCT( fd_msg_browse(avp, MSG_BRW_NEXT, &avp, NULL) );
231                                                }
232
233                                        }
234                               
235                                        break;
236                       
237                        }
238                }
239               
240                if (is_match) {
241                        /* We found the first rule that matches for this message */
242                        *found = r;
243                        break;
244                }
245        }
246       
247        return 0;
248}
249
250/* The forward callback */
251int ard_rule_apply(void * cbdata, struct msg ** msg)
252{
253        struct ard_rule * rule = NULL;
254       
255        TRACE_ENTRY("%p %p", cbdata, msg);
256        CHECK_PARAMS(msg && *msg);
257       
258        /* First, check if we have a rule that applies to this message */
259        CHECK_FCT( find_rule(*msg, &rule) );
260       
261        if (rule) {
262                struct avp * avp;
263                union avp_value val;
264                struct fd_list * li;
265               
266                /* We have to reply a Redirect message in this case */
267                CHECK_FCT( fd_msg_new_answer_from_req(fd_g_config->cnf_dict, msg, MSGFL_ANSW_ERROR) );
268               
269                CHECK_FCT( fd_msg_rescode_set( *msg, "DIAMETER_REDIRECT_INDICATION", NULL, NULL, 1 ) );
270               
271                /* Now add the Redirect-* AVPs */
272                CHECK_FCT( fd_msg_avp_new( avp_Redirect_Host_Usage, 0, &avp ) );
273                val.u32 = rule->type;
274                CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
275                CHECK_FCT( fd_msg_avp_add( *msg, MSG_BRW_LAST_CHILD, avp ) );
276               
277                if (rule->type) {
278                        CHECK_FCT( fd_msg_avp_new( avp_Redirect_Max_Cache_Time, 0, &avp ) );
279                        val.u32 = rule->rct ?: ard_conf->default_rct;
280                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
281                        CHECK_FCT( fd_msg_avp_add( *msg, MSG_BRW_LAST_CHILD, avp ) );
282                }
283               
284                for (li = rule->targets.next; li != &rule->targets; li = li->next) {
285                        struct ard_target * t = li->o;
286                       
287                        CHECK_FCT( fd_msg_avp_new( avp_Redirect_Host, 0, &avp ) );
288                        val.os.data = t->s;
289                        val.os.len  = t->l;
290                        CHECK_FCT( fd_msg_avp_setvalue( avp, &val ) );
291                        CHECK_FCT( fd_msg_avp_add( *msg, MSG_BRW_LAST_CHILD, avp ) );
292                }
293               
294                /* Send this answer */
295                CHECK_FCT( fd_msg_send( msg, NULL, NULL) );
296        }
297       
298        return 0;
299}
300
Note: See TracBrowser for help on using the repository browser.