textopsx.c

00001 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <fnmatch.h>
00031 
00032 #include "../../sr_module.h"
00033 #include "../../dprint.h"
00034 #include "../../data_lump.h"
00035 #include "../../msg_translator.h"
00036 #include "../../tcp_options.h"
00037 #include "../../mod_fix.h"
00038 
00039 #include "api.h"
00040 
00041 MODULE_VERSION
00042 
00043 static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2);
00044 
00045 static int change_reply_status_f(sip_msg_t*, char*, char*);
00046 static int change_reply_status_fixup(void** param, int param_no);
00047 
00048 static int w_keep_hf_f(sip_msg_t*, char*, char*);
00049 
00050 static int w_fnmatch2_f(sip_msg_t*, char*, char*);
00051 static int w_fnmatch3_f(sip_msg_t*, char*, char*, char*);
00052 static int fixup_fnmatch(void** param, int param_no);
00053 
00054 static int w_remove_body_f(struct sip_msg*, char*, char *);
00055 static int bind_textopsx(textopsx_api_t *tob);
00056 
00057 static int mod_init(void);
00058 
00059 /* cfg functions */
00060 static cmd_export_t cmds[] = {
00061         {"msg_apply_changes",    (cmd_function)msg_apply_changes_f,     0,
00062                 0, REQUEST_ROUTE },
00063         {"change_reply_status",  change_reply_status_f,                 2,
00064                 change_reply_status_fixup, ONREPLY_ROUTE },
00065         {"remove_body",          (cmd_function)w_remove_body_f,         0,
00066                 0, ANY_ROUTE },
00067         {"keep_hf",              (cmd_function)w_keep_hf_f,             1,
00068                 fixup_regexp_null, ANY_ROUTE },
00069         {"fnmatch",              (cmd_function)w_fnmatch2_f,            2,
00070                 fixup_fnmatch, ANY_ROUTE },
00071         {"fnmatch",              (cmd_function)w_fnmatch3_f,            3,
00072                 fixup_fnmatch, ANY_ROUTE },
00073         {"bind_textopsx",        (cmd_function)bind_textopsx,           1,
00074                 0, ANY_ROUTE },
00075 
00076 
00077         {0,0,0,0,0}
00078 };
00079 
00080 /* module exports structure */
00081 struct module_exports exports= {
00082         "textopsx",
00083         cmds, /* cfg functions */
00084         0, /* RPC methods */
00085         0, /* cfg parameters */
00086         mod_init, /* initialization function */
00087         0, /* response function */
00088         0, /* destroy function */
00089         0, /* on_cancel function */
00090         0  /* per-child init function */
00091 };
00092 
00093 
00097 static int mod_init(void)
00098 {
00099 #ifdef USE_TCP
00100         tcp_set_clone_rcvbuf(1);
00101 #endif
00102         return 0;
00103 }
00104 
00108 static int msg_apply_changes_f(sip_msg_t *msg, char *str1, char *str2)
00109 {
00110         struct dest_info dst;
00111         str obuf;
00112         sip_msg_t tmp;
00113 
00114         if(get_route_type()!=REQUEST_ROUTE)
00115         {
00116                 LM_ERR("invalid usage - not in request route\n");
00117                 return -1;
00118         }
00119 
00120         init_dest_info(&dst);
00121         dst.proto = PROTO_UDP;
00122         obuf.s = build_req_buf_from_sip_req(msg,
00123                         (unsigned int*)&obuf.len, &dst,
00124                         BUILD_NO_LOCAL_VIA|BUILD_NO_VIA1_UPDATE);
00125         if(obuf.s == NULL)
00126         {
00127                 LM_ERR("couldn't update msg buffer content\n");
00128                 return -1;
00129         }
00130         if(obuf.len>=BUF_SIZE)
00131         {
00132                 LM_ERR("new buffer overflow (%d)\n", obuf.len);
00133                 pkg_free(obuf.s);
00134                 return -1;
00135         }
00136         /* temporary copy */
00137         memcpy(&tmp, msg, sizeof(sip_msg_t));
00138 
00139         /* reset dst uri and path vector to avoid freeing - restored later */
00140         if(msg->dst_uri.s!=NULL)
00141         {
00142                 msg->dst_uri.s = NULL;
00143                 msg->dst_uri.len = 0;
00144         }
00145         if(msg->path_vec.s!=NULL)
00146         {
00147                 msg->path_vec.s = NULL;
00148                 msg->path_vec.len = 0;
00149         }
00150 
00151         /* free old msg structure */
00152         free_sip_msg(msg);
00153         memset(msg, 0, sizeof(sip_msg_t));
00154 
00155         /* restore msg fields */
00156         msg->buf                = tmp.buf;
00157         msg->id                 = tmp.id;
00158         msg->rcv                = tmp.rcv;
00159         msg->set_global_address = tmp.set_global_address;
00160         msg->set_global_port    = tmp.set_global_port;
00161         msg->flags              = tmp.flags;
00162         msg->msg_flags          = tmp.msg_flags;
00163         msg->hash_index         = tmp.hash_index;
00164         msg->force_send_socket  = tmp.force_send_socket;
00165         msg->fwd_send_flags     = tmp.fwd_send_flags;
00166         msg->rpl_send_flags     = tmp.rpl_send_flags;
00167         msg->dst_uri            = tmp.dst_uri;
00168         msg->path_vec           = tmp.path_vec;
00169 
00170         memcpy(msg->buf, obuf.s, obuf.len);
00171         msg->len = obuf.len;
00172         msg->buf[msg->len] = '\0';
00173 
00174         /* free new buffer - copied in the static buffer from old sip_msg_t */
00175         pkg_free(obuf.s);
00176 
00177         /* reparse the message */
00178         LM_DBG("SIP Request content updated - reparsing\n");
00179         if (parse_msg(msg->buf, msg->len, msg)!=0){
00180                 LM_ERR("parse_msg failed\n");
00181                 return -1;
00182         }
00183 
00184         return 1;
00185 }
00186 
00187 
00191 static int change_reply_status_fixup(void** param, int param_no)
00192 {
00193         if (param_no == 1) {
00194                 return fixup_var_int_12(param, param_no);
00195         } else if (param_no == 2)
00196                 return fixup_var_pve_str_12(param, param_no);
00197         else
00198                 return 0;
00199 }
00200 
00204 static int change_reply_status_f(struct sip_msg* msg, char* _code, char* _reason)
00205 {
00206         int     code;
00207         str     reason;
00208         struct lump     *l;
00209         char    *ch;
00210 
00211         if (get_int_fparam(&code, msg, (fparam_t*)_code)
00212                 || get_str_fparam(&reason, msg, (fparam_t*)_reason)
00213                 || (reason.len == 0)
00214         ) {
00215                 LOG(L_ERR, "ERROR: textops: cannot get parameter\n");
00216                 return -1;
00217         }
00218 
00219         if ((code < 100) || (code > 699)) {
00220                 LOG(L_ERR, "ERROR: textops: wrong status code: %d\n",
00221                                 code);
00222                 return -1;
00223         }
00224 
00225         if (((code < 300) || (msg->REPLY_STATUS < 300))
00226                 && (code/100 != msg->REPLY_STATUS/100)
00227         ) {
00228                 LOG(L_ERR, "ERROR: textops: the class of provisional or "
00229                         "positive final replies cannot be changed\n");
00230                 return -1;
00231         }
00232 
00233         /* rewrite the status code directly in the message buffer */
00234         msg->first_line.u.reply.statuscode = code;
00235         msg->first_line.u.reply.status.s[2] = code % 10 + '0'; code /= 10;
00236         msg->first_line.u.reply.status.s[1] = code % 10 + '0'; code /= 10;
00237         msg->first_line.u.reply.status.s[0] = code + '0';
00238 
00239         l = del_lump(msg,
00240                 msg->first_line.u.reply.reason.s - msg->buf,
00241                 msg->first_line.u.reply.reason.len,
00242                 0);
00243         if (!l) {
00244                 LOG(L_ERR, "ERROR: textops(): Failed to add del lump\n");
00245                 return -1;
00246         }
00247         /* clone the reason phrase, the lumps need to be pkg allocated */
00248         ch = (char *)pkg_malloc(reason.len);
00249         if (!ch) {
00250                 LOG(L_ERR, "ERROR: textops: Not enough memory\n");
00251                 return -1;
00252         }
00253         memcpy(ch, reason.s, reason.len);
00254         if (insert_new_lump_after(l, ch, reason.len, 0)==0){
00255                 LOG(L_ERR, "ERROR: textops: failed to add new lump: %.*s\n",
00256                         reason.len, ch);
00257                 pkg_free(ch);
00258                 return -1;
00259         }
00260 
00261         return 1;
00262 }
00263 
00264 
00268 static int w_remove_body_f(struct sip_msg *msg, char *p1, char *p2)
00269 {
00270         str body = {0,0};
00271 
00272         body.len = 0;
00273         body.s = get_body(msg);
00274         if (body.s==0)
00275         {
00276                 LM_DBG("no body in the message\n");
00277                 return 1;
00278         }
00279         body.len = msg->buf + msg->len - body.s;
00280         if (body.len<=0)
00281         {
00282                 LM_DBG("empty body in the message\n");
00283                 return 1;
00284         }
00285         if(del_lump(msg, body.s - msg->buf, body.len, 0) == 0)
00286         {
00287                 LM_ERR("cannot remove body\n");
00288                 return -1;
00289         }
00290         return 1;
00291 }
00292 
00293 
00297 static int w_keep_hf_f(struct sip_msg* msg, char* key, char* foo)
00298 {
00299         struct hdr_field *hf;
00300         regex_t *re;
00301         regmatch_t pmatch;
00302         char c;
00303         struct lump* l;
00304 
00305         re = (regex_t*)key;
00306 
00307         /* we need to be sure we have seen all HFs */
00308         parse_headers(msg, HDR_EOH_F, 0);
00309         for (hf=msg->headers; hf; hf=hf->next)
00310         {
00311                 switch(hf->type) {
00312                         case HDR_FROM_T:
00313                         case HDR_TO_T:
00314                         case HDR_CALLID_T:
00315                         case HDR_CSEQ_T:
00316                         case HDR_VIA_T:
00317                         case HDR_VIA2_T:
00318                         case HDR_CONTACT_T:
00319                         case HDR_CONTENTLENGTH_T:
00320                         case HDR_CONTENTTYPE_T:
00321                         case HDR_ROUTE_T:
00322                         case HDR_RECORDROUTE_T:
00323                         case HDR_MAXFORWARDS_T:
00324                                 continue;
00325                         default:
00326                                 ;
00327                 }
00328 
00329                 c = hf->name.s[hf->name.len];
00330                 hf->name.s[hf->name.len] = '\0';
00331                 if (regexec(re, hf->name.s, 1, &pmatch, 0)!=0)
00332                 {
00333                         /* no match => remove */
00334                         hf->name.s[hf->name.len] = c;
00335                         l=del_lump(msg, hf->name.s-msg->buf, hf->len, 0);
00336                         if (l==0)
00337                         {
00338                                 LM_ERR("cannot remove header\n");
00339                                 return -1;
00340                         }
00341                 } else {
00342                         hf->name.s[hf->name.len] = c;
00343                 }
00344         }
00345 
00346         return -1;
00347 }
00348 
00352 static int w_fnmatch(str *val, str *match, str *flags)
00353 {
00354         int i;
00355         i = 0;
00356 #ifdef FNM_CASEFOLD
00357         if(flags && (flags->s[0]=='i' || flags->s[0]=='I'))
00358                 i = FNM_CASEFOLD;
00359 #endif
00360         if(fnmatch(match->s, val->s, i)==0)
00361                 return 0;
00362         return -1;
00363 }
00364 
00368 static int w_fnmatch2_f(sip_msg_t *msg, char *val, char *match)
00369 {
00370         str sval;
00371         str smatch;
00372         if(get_str_fparam(&sval, msg, (fparam_t*)val)<0
00373                         || get_str_fparam(&smatch, msg, (fparam_t*)match)<0)
00374         {
00375                 LM_ERR("invalid parameters");
00376                 return -1;
00377         }
00378         if(w_fnmatch(&sval, &smatch, NULL)<0)
00379                 return -1;
00380         return 1;
00381 }
00382 
00386 static int w_fnmatch3_f(sip_msg_t *msg, char *val, char *match, char *flags)
00387 {
00388         str sval;
00389         str smatch;
00390         str sflags;
00391         if(get_str_fparam(&sval, msg, (fparam_t*)val)<0
00392                         || get_str_fparam(&smatch, msg, (fparam_t*)match)<0
00393                         || get_str_fparam(&sflags, msg, (fparam_t*)flags)<0)
00394         {
00395                 LM_ERR("invalid parameters");
00396                 return -1;
00397         }
00398         if(w_fnmatch(&sval, &smatch, &sflags)<0)
00399                 return -1;
00400         return 1;
00401 }
00402 
00406 static int fixup_fnmatch(void** param, int param_no)
00407 {
00408         if (param_no == 1) {
00409                 return fixup_var_pve_12(param, param_no);
00410         } else if (param_no == 2) {
00411                 return fixup_var_pve_12(param, param_no);
00412         } else if (param_no == 3) {
00413                 return fixup_var_pve_12(param, param_no);
00414         } else {
00415                 return 0;
00416         }
00417 
00418 }
00419 
00420 /*
00421  * Function to load the textops api.
00422  */
00423 static int bind_textopsx(textopsx_api_t *tob){
00424         if(tob==NULL){
00425                 LM_WARN("textopsx_binds: Cannot load textopsx API into a NULL pointer\n");
00426                 return -1;
00427         }
00428         tob->msg_apply_changes = msg_apply_changes_f;
00429         return 0;
00430 }