static inline int check_against_rule_list(struct ip_addr *ip, str *text, unsigned short port, unsigned short proto, int i) { struct bl_rule *p; int t_val; int ret = 0; LM_DBG("using list %.*s \n", blst_heads[i].name.len, blst_heads[i].name.s); if( !blst_heads[i].flags&BL_READONLY_LIST ) { /* get list for read */ lock_get( blst_heads[i].lock ); while(blst_heads[i].count_write) { lock_release( blst_heads[i].lock ); sleep_us(5); lock_get( blst_heads[i].lock ); } blst_heads[i].count_read++; lock_release(blst_heads[i].lock); } for(p = blst_heads[i].first ; p ; p = p->next) { t_val = (p->port==0 || p->port==port) && (p->proto==PROTO_NONE || p->proto==proto) && (matchnet(ip, &(p->ip_net)) == 1) && (p->body.s==NULL || !fnmatch(p->body.s, text->s, 0)); if(!!(p->flags & BLR_APPLY_CONTRARY) ^ !!(t_val)){ ret = 1; LM_DBG("matched list %.*s \n", blst_heads[i].name.len,blst_heads[i].name.s); break; } } if( !blst_heads[i].flags&BL_READONLY_LIST ) { lock_get( blst_heads[i].lock ); blst_heads[i].count_read--; lock_release(blst_heads[i].lock); } return ret; }
/*! \brief eval_elem helping function, returns an op param */ inline static int comp_ip(struct sip_msg *msg, int op, struct ip_addr* ip, operand_t *opd) { struct hostent* he; char ** h; int ret; str tmp; ret=-1; switch(opd->type){ case NET_ST: switch(op){ case EQUAL_OP: ret=(matchnet(ip, (struct net*)opd->v.data)==1); break; case DIFF_OP: ret=(matchnet(ip, (struct net*)opd->v.data)!=1); break; default: goto error_op; } break; case STR_ST: case RE_ST: switch(op){ case EQUAL_OP: case MATCH_OP: /* 1: compare with ip2str*/ ret=comp_str(ip_addr2a(ip), opd->v.data, op, opd->type); if (ret==1) break; /* 2: resolve (name) & compare w/ all the ips */ if (opd->type==STR_ST){ he=resolvehost((char*)opd->v.data,0); if (he==0){ LM_DBG("could not resolve %s\n",(char*)opd->v.data); }else if (he->h_addrtype==(int)ip->af){ for(h=he->h_addr_list;(ret!=1)&& (*h); h++){ ret=(memcmp(ip->u.addr, *h, ip->len)==0); } if (ret==1) break; } } /* 3: (slow) rev dns the address * and compare with all the aliases * !!??!! review: remove this? */ if(received_dns & DO_REV_DNS) { he=rev_resolvehost(ip); if (he==0){ print_ip("comp_ip: could not rev_resolve ip" " address: ", ip, "\n"); ret=0; }else{ /* compare with primary host name */ ret=comp_str(he->h_name, opd->v.data, op, opd->type); /* compare with all the aliases */ for(h=he->h_aliases; (ret!=1) && (*h); h++){ ret=comp_str(*h, opd->v.data, op, opd->type); } } } else { return 0; } break; case DIFF_OP: ret=comp_ip(msg, op, ip, opd); if (ret>=0) ret=!ret; break; default: goto error_op; } break; case MYSELF_ST: /* check if it's one of our addresses*/ tmp.s=ip_addr2a(ip); tmp.len=strlen(tmp.s); ret=check_self_op(op, &tmp, 0); break; default: LM_CRIT("invalid type for src_ip or dst_ip (%d)\n", opd->type); ret=-1; } return ret; error_op: LM_CRIT("invalid operator %d\n", op); return -1; }
/* receive an ipv4 udp packet over a raw socket. * The packet is copied in *buf and *buf is advanced to point to the * payload. Fills from and to. * @param rsock - raw socket * @param buf - the packet will be written to where *buf points intially and * then *buf will be advanced to point to the udp payload. * @param len - buffer length (should be enough to hold at least the * ip and udp headers + 1 byte). * @param from - result parameter, filled with source address and port of the * packet. * @param from - result parameter, filled with destination (local) address and * port of the packet. * @param rf - filter used to decide whether or not the packet is * accepted/processed. If null, all the packets are accepted. * @return packet len or <0 on error (-1 and -2 on recv error @see recvpkt4, * -3 if the headers are invalid and -4 if the packet doesn't * match the filter). */ int raw_udp4_recv(int rsock, char** buf, int len, union sockaddr_union* from, union sockaddr_union* to, struct raw_filter* rf) { int n; unsigned short dst_port; unsigned short src_port; struct ip_addr dst_ip; char* end; char* udph_start; char* udp_payload; struct ip iph; struct udphdr udph; unsigned short udp_len; n=recvpkt4(rsock, *buf, len, from, to); if (unlikely(n<0)) goto error; end=*buf+n; if (unlikely(n<((sizeof(struct ip) * raw_ipip ? 2 : 1)+sizeof(struct udphdr)))) { n=-3; goto error; } if(raw_ipip) *buf = *buf + sizeof(struct ip); /* FIXME: if initial buffer is aligned, one could skip the memcpy and directly cast ip and udphdr pointer to the memory */ memcpy(&iph, *buf, sizeof(struct ip)); udph_start=*buf+iph.ip_hl*4; udp_payload=udph_start+sizeof(struct udphdr); if (unlikely(udp_payload>end)){ n=-3; goto error; } memcpy(&udph, udph_start, sizeof(struct udphdr)); udp_len=ntohs(udph.uh_ulen); if (unlikely((udph_start+udp_len)!=end)){ if ((udph_start+udp_len)>end){ n=-3; goto error; }else{ ERR("udp length too small: %d/%d\n", (int)udp_len, (int)(end-udph_start)); n=-3; goto error; } } /* advance buf */ *buf=udp_payload; n=(int)(end-*buf); /* fill ip from the packet (needed if no PKT_INFO is used) */ dst_ip.af=AF_INET; dst_ip.len=4; dst_ip.u.addr32[0]=iph.ip_dst.s_addr; /* fill dst_port */ dst_port=ntohs(udph.uh_dport); ip_addr2su(to, &dst_ip, dst_port); /* fill src_port */ src_port=ntohs(udph.uh_sport); su_setport(from, src_port); if (likely(rf)) { su2ip_addr(&dst_ip, to); if ( (dst_port && rf->port1 && ((dst_port<rf->port1) || (dst_port>rf->port2)) ) || (matchnet(&dst_ip, &rf->dst)!=1) ){ /* no match */ n=-4; goto error; } } error: return n; }
/* eval_elem helping function, returns an op param */ inline static int comp_ip(struct ip_addr* ip, void* param, int op, int subtype) { struct hostent* he; char ** h; int ret; str tmp; ret=-1; switch(subtype){ case NET_ST: switch(op){ case EQUAL_OP: ret=(matchnet(ip, (struct net*) param)==1); break; case DIFF_OP: ret=(matchnet(ip, (struct net*) param)!=1); break; default: goto error_op; } break; case STRING_ST: case RE_ST: switch(op){ case EQUAL_OP: case MATCH_OP: /* 1: compare with ip2str*/ ret=comp_str(ip_addr2a(ip), param, op, subtype); if (ret==1) break; /* 2: resolve (name) & compare w/ all the ips */ if (subtype==STRING_ST){ he=resolvehost((char*)param); if (he==0){ DBG("comp_ip: could not resolve %s\n", (char*)param); }else if (he->h_addrtype==ip->af){ for(h=he->h_addr_list;(ret!=1)&& (*h); h++){ ret=(memcmp(ip->u.addr, *h, ip->len)==0); } if (ret==1) break; } } /* 3: (slow) rev dns the address * and compare with all the aliases * !!??!! review: remove this? */ he=rev_resolvehost(ip); if (he==0){ print_ip( "comp_ip: could not rev_resolve ip address:" " ", ip, "\n"); ret=0; }else{ /* compare with primary host name */ ret=comp_str(he->h_name, param, op, subtype); /* compare with all the aliases */ for(h=he->h_aliases; (ret!=1) && (*h); h++){ ret=comp_str(*h, param, op, subtype); } } break; case DIFF_OP: ret=comp_ip(ip, param, EQUAL_OP, subtype); if (ret>=0) ret=!ret; break; default: goto error_op; } break; case MYSELF_ST: /* check if it's one of our addresses*/ tmp.s=ip_addr2a(ip); tmp.len=strlen(tmp.s); ret=check_self_op(op, &tmp, 0); break; default: LOG(L_CRIT, "BUG: comp_ip: invalid type for " " src_ip or dst_ip (%d)\n", subtype); ret=-1; } return ret; error_op: LOG(L_CRIT, "BUG: comp_ip: invalid operator %d\n", op); return -1; }