#include #include #ifdef CONFIG_KMOD #include #endif #include #include #include #include #ifdef CONFIG_IP_MASQUERADE_MOD #include #endif #include #include #include #include #include static struct server server_list[] = { {"ace", 0x80c6c0c6}, /*128.198.192.198*/ {"vinci", 0x80c6c0c1}, /*128.198.192.193*/ {"oblib", 0x80c6c0c3}, {"gandalf", 0x80c6c0c2}, {"default", 0x00000000}, {"frodo", 0x80c6c0b7}, /*128.198.192.183*/ {"wait", 0x80c6c0ca}, /*128.198.192.202*/ {"reject", 0xffffffff} }; extern struct ip_vs_cb_rule_field rule_fields[]; extern int num_rule_fields; int num_servers = sizeof(server_list) / sizeof(struct server); struct ip_sticky ip_sticky_list[20]; int sticky_num = 0; /* * Global variables of the module * that should be set for each request */ int max_char_len = 0; char *c_cr = NULL; char *c_lf = NULL; char *c_sp = NULL; char *c_la = NULL; char *c_ra = NULL; char *c_fs = NULL; char *c_ex = NULL; int len_cr = 0; int len_lf = 0; int len_sp = 0; int len_la = 0; int len_ra = 0; int len_fs = 0; int len_ex = 0; char url[256]; char *mstrstr(char *source, char *substr, size_t n); int get_content_type(char *buf, int buf_len, char *htp_mthd_nm); int xml_tag_parser(char *buf, int buf_len); int get_tag_range(char *tag, int pos, char *hay_begin, char *hay_end, char **needle_begin, char **needle_end); void clear_rule_fld_values(); __u32 check_sticky(__u32 addr) { int i = 0; for(i = 0; i < sticky_num; i++) { if(addr == ip_sticky_list[i].source_ip) { IP_RULE_MSG("sticky found on %x\n",ip_sticky_list[i].dest_ip); return ip_sticky_list[i].dest_ip; } } return 0; } __u32 route_to(char *server_name, int sticky_flag, __u32 saddr) { int i = 0; __u32 dest_addr = 0; for(i = 0; i < num_servers; i++) { if(strcmp(server_name, server_list[i].name) == 0) { if(sticky_flag == STICKY_ON_IP) { /*printk("###### SERVER_ROUTE_TO= STICKY \n");*/ ip_sticky_list[sticky_num].dest_ip = server_list[i].addr; ip_sticky_list[sticky_num].source_ip = saddr; sticky_num++; /*printk("##### in route_to sticky_num=%d\n",sticky_num);*/ } dest_addr = server_list[i].addr; break; } } return dest_addr; } __u32 module_rule_matching(struct sk_buff *skb) { struct iphdr *iph = NULL; int data_len = 0; unsigned char *data_p = NULL; int ret = 0; __u32 ret_addr = 0; __u32 saddr = 0, daddr = 0; __u16 sport = 0, dport = 0; __u8 protocol = 0; union ip_masq_tphdr h; char htp_mthd_nm[20]; MOD_INC_USE_COUNT; iph = skb->nh.iph; h.raw = (char*) iph + iph->ihl * 4; saddr = ntohl(iph->saddr); daddr = ntohl(iph->daddr); sport = ntohs(h.th->source); dport = ntohs(h.th->dest); protocol = iph->protocol; if((ret_addr = check_sticky(saddr)) > 0) goto return_directly; data_p = skb->data + iph->ihl*4 + h.th->doff * 4; data_len = skb->len - (iph->ihl*4 + h.th->doff*4); if(data_len <= 0) { IP_RULE_MSG("No data found data len = %d", data_len); goto return_directly; } ret = get_content_type((char*)data_p, data_len, htp_mthd_nm); if(ret >= 0) { if(strcmp(htp_mthd_nm, "GET")) ret = xml_tag_parser((char*)data_p, data_len); if(ret >= 0) { ret_addr = rule_configure(saddr, daddr, sport, dport, protocol); clear_rule_fld_values(); } } return_directly: MOD_DEC_USE_COUNT; IP_RULE_MSG("Returned address=%x\n", ret_addr); return ret_addr; } int get_content_type(char *buf, int buf_len, char *htp_mthd_nm) { int ret = -1; char *p = NULL; char *p1 = NULL; /* * First copy out the url value */ if((p = (char *)memchr(buf, ' ', buf_len)) != NULL) { memcpy(htp_mthd_nm, buf, p - buf); htp_mthd_nm[p - buf] = '\0'; while((*p) == ' ') p++; if((p1 = (char *)memchr(p, ' ', buf_len - (p - buf))) != NULL) { memcpy(url, p, p1 - p); url[p1 - p] = '\0'; IP_RULE_MSG("HTTP MTHD=%s URI value = '%s'\n", htp_mthd_nm, url); } else { IP_RULE_MSG("Invalid buffer. No space after URI\n"); return -1; } } else { IP_RULE_MSG("Invalid buffer. No space before URI\n"); return -1; } /* * Now determine the content type */ if(!strcmp(htp_mthd_nm, "GET")) ret = 0; else if(((p = mstrstr(buf, "Content-Type:", buf_len)) != NULL) || ((p = mstrstr(buf, "Content-type:", buf_len)) != NULL)) { p1 = (char *)memchr(p, CR, buf_len - (p - buf)); if(p1 != NULL) { /* * Place p past the ':' */ p += 13; if((p1 = mstrstr(p, "x-www-form-urlencoded", buf_len - (p - buf))) != NULL) { IP_RULE_MSG("Content type is 'x-www-form-urlencoded'\n"); c_cr = UE_CR; c_lf = UE_LF; c_sp = UE_SP; c_la = UE_LA; c_ra = UE_RA; c_fs = UE_FS; c_ex = UE_EX; max_char_len = 3; ret = 0; } else if((p1 = mstrstr(p, "text/xml", buf_len - (p - buf))) != NULL) { IP_RULE_MSG("Content type is 'text/xml'\n"); c_cr = PL_CR; c_lf = PL_LF; c_sp = PL_SP; c_la = PL_LA; c_ra = PL_RA; c_fs = PL_FS; c_ex = PL_EX; max_char_len = 1; ret = 0; } if(ret >= 0) { len_cr = strlen(c_cr); len_lf = strlen(c_lf); len_sp = strlen(c_sp); len_la = strlen(c_la); len_ra = strlen(c_ra); len_fs = strlen(c_fs); len_ex = strlen(c_ex); } } } return ret; } int xml_tag_parser(char *buf, int buf_len) { int ret = 0; int field_count = 0; short done_yet = 0; int skip_len = 0; int pos = 0; char tag[64]; char pos_str[10]; char *p = NULL; char *p1 = NULL; char *fld_spec_beg = NULL; char *fld_spec_end = NULL; char *data_beg = NULL; char *data_end = NULL; char *tag_beg = NULL; char *tag_end = NULL; for(field_count = 0; field_count < num_rule_fields; field_count++) { fld_spec_beg = &(rule_fields[field_count].name[0]); fld_spec_end = &(rule_fields[field_count].name[strlen(rule_fields[field_count].name)]); data_beg = buf; data_end = buf + buf_len; while(fld_spec_beg < fld_spec_end) { p = (char *)memchr(fld_spec_beg, ':', fld_spec_end - fld_spec_beg); if(!p) { IP_RULE_MSG("Invalid rule field specification '%s'\n", rule_fields[field_count].name); return -1; } memcpy(tag, fld_spec_beg, p - fld_spec_beg); tag[p - fld_spec_beg] = '\0'; p += 1; p1 = (char *)memchr(p, '.', fld_spec_end - p); if(!p1) { IP_RULE_MSG("Invalid rule field specification '%s'\n", rule_fields[field_count].name); return -1; } memcpy(pos_str, p, p1 - p); pos_str[p1 - p] = '\0'; fld_spec_beg = ++p1; pos = simple_strtol(&(pos_str[0]), (char **) NULL, 10); get_tag_range(tag, pos, data_beg, data_end, &tag_beg, &tag_end); if((!tag_beg) || (!tag_end)) { IP_RULE_MSG("get_tag_range() returned NULL either for tag_beg or tag_end, " "tag_beg=%u, " "tag_end=%u, " "tag=%s, " "pos=%d ", ((tag_beg) ? (unsigned int) tag_beg : 0), ((tag_end) ? (unsigned int) tag_end : 0), tag, pos); return -1; } if(fld_spec_beg == fld_spec_end) { /* We have parsed all the sub fields of the field specified in the rule. * Now parse data between tag_beg and tag_end and store in the field value * after skipping white spaces, carriage returns and line feeds. */ done_yet = 0; while((tag_beg < tag_end) && !done_yet) { done_yet = 1; skip_len = len_sp; if(!memcmp(tag_beg, c_sp, skip_len)) { tag_beg += skip_len; done_yet = 0; } skip_len = len_cr; if(!memcmp(tag_beg, c_cr, skip_len)) { tag_beg += skip_len; done_yet = 0; } skip_len = len_lf; if(!memcmp(tag_beg, c_lf, skip_len)) { tag_beg += skip_len; done_yet = 0; } } done_yet = 0; while((tag_beg < tag_end) && !done_yet) { skip_len = len_sp; if(memcmp(tag_end - skip_len, c_sp, skip_len)) skip_len = 0; if(!skip_len) { skip_len = len_cr; if(memcmp(tag_end - skip_len, c_cr, skip_len)) skip_len = 0; } if(!skip_len) { skip_len = len_lf; if(memcmp(tag_end - skip_len, c_lf, skip_len)) skip_len = 0; } if(skip_len) tag_end -= skip_len; else done_yet = 1; } if(tag_beg != tag_end) { if((tag_end - tag_beg) < sizeof(rule_fields[field_count].value)) { memcpy(rule_fields[field_count].value, tag_beg, tag_end - tag_beg); rule_fields[field_count].value[tag_end - tag_beg] = '\0'; } else IP_RULE_MSG("tag value size=%d is larger than its container size=%d for rule tag '%s' of field spec '%s'\n", (tag_end - tag_beg), sizeof(rule_fields[field_count].value), tag, rule_fields[field_count].name); } else IP_RULE_MSG("No value found for rule field spec '%s'\n", rule_fields[field_count].name); } else { data_beg = tag_beg; data_end = tag_end; } } } return ret; } int get_tag_range(char *tag, int pos, char *hay_begin, char *hay_end, char **needle_begin, char **needle_end) { char temp_buf[67]; int curr_pos = 0; int skip_len = 0; int hay_len = 0; int buf_len = 0; char *p = NULL; char *p_tmp = NULL; char *p1 = NULL; char *p_end = NULL; char *p_beg = NULL; char *tag_left = NULL; char *tag_right = NULL; hay_len = hay_end - hay_begin; buf_len = hay_len; p = hay_begin; while(curr_pos < pos) { /* * First Remove any leading comments */ sprintf(temp_buf, "%s%s--", c_la, c_ex); if((p_tmp = mstrstr(p, temp_buf, hay_len)) != NULL) { /* * Found the beginning of comment marker "" */ sprintf(temp_buf, "--%s", c_ra); if((p1 = mstrstr(p_tmp, temp_buf, buf_len - (p_tmp - hay_begin))) != NULL) { p = p1 + strlen(temp_buf); hay_len = buf_len - (p - hay_begin); continue; } else { IP_RULE_MSG("Bad xml data, no ending comment tag\n"); break; } } sprintf(temp_buf, "%s%s", c_fs, tag); /* * First look for end position "/tag" i.e., the vicinity of */ if((p_end = mstrstr(p, temp_buf, hay_len)) != NULL) { curr_pos++; if(curr_pos == pos) { /* * Now look for begin position of the "tag" i.e., the vicinity of */ if((p_beg = mstrstr(p, tag, hay_len)) != NULL) { /* * First verify that it is a real tag */ tag_left = p_beg; tag_right = p_beg + strlen(tag); /* * i.e, Below is a check for situations like AtagB */ if(( (memcmp(tag_left - len_sp, c_sp, len_sp)) && (memcmp(tag_left - len_ra, c_la, len_la)) && (memcmp(tag_left - len_cr, c_cr, len_cr)) && (memcmp(tag_left - len_lf, c_lf, len_lf)) ) || ( (memcmp(tag_right, c_sp, len_sp)) && (memcmp(tag_right, c_ra, len_ra)) && (memcmp(tag_right, c_cr, len_cr)) && (memcmp(tag_right, c_lf, len_lf)) ) ) { p = tag_right; hay_len = buf_len - (p - hay_begin); --curr_pos; continue; } p_beg = tag_right; /* * Find the position of '>' for p_beg */ p = mstrstr(p_beg, c_ra, p_end - p_beg); if(p == NULL) { p_beg = NULL; p_end = NULL; break; } /* * Find the position of '<' for beginning from p_beg */ p_tmp = mstrstr(p_beg, c_la, p_end - p_beg); /* * Below is a check for tag */ if(p_tmp && (p_tmp < p)) { hay_len = buf_len - (p - hay_begin); --curr_pos; continue; } /* * Now eliminate all unwanted characters between p_beg and p_end * such as white space, line feed, carriage return until until * right and left anchors are seen respectively */ if(p != NULL) p_beg = p + len_ra; else { /* * We didn't find the '>' for p_beg */ p_beg = NULL; p_end = NULL; break; } /* * Find the position of left anchor for p_end */ while((p_end - max_char_len) > p_beg) { skip_len = len_la; if(!memcmp(p_end - skip_len, c_la, skip_len)) { p_end -= skip_len; break; } skip_len = len_sp; if(!memcmp(p_end - skip_len, c_sp, skip_len)) p_end -= skip_len; skip_len = len_cr; if(!memcmp(p_end - skip_len, c_cr, skip_len)) p_end -= skip_len; skip_len = len_lf; if(!memcmp(p_end - skip_len, c_lf, skip_len)) p_end -= skip_len; } } } else { /* * Advance p for the next ...data... block */ p = p_end + strlen(temp_buf); hay_len = buf_len - (p - hay_begin); } } else /* * No specified needle found in the hay */ break; } *needle_begin = p_beg; *needle_end = p_end; return 0; } char *mstrstr(char *source, char *substr, size_t n) { char c = source[n - 1]; char *p = NULL; int subStrLen = 0; /* * Following is needed to make strstr work */ source[n - 1] = '\0'; p = strstr(source, substr); source[n - 1] = c; if(p == NULL) { subStrLen = strlen(substr); if(!memcmp(source + n - subStrLen, substr, subStrLen)) p = source + n - subStrLen; } return p; } void clear_rule_fld_values() { int i = 0; for(i = 0; i < num_rule_fields; i++) rule_fields[i].value[0] = '\0'; } void register_rule_matching() { sticky_num = 0; rule_matching = module_rule_matching; } void unregister_rule_matching() { rule_matching = ip_cs_norule; } int init_module(void) { register_rule_matching(); clear_rule_fld_values(); IP_RULE_MSG("RULE MATCHING MODULE INSERTED num_servers=%d num_rule_fields=%d\n", num_servers, num_rule_fields); return 0; } void cleanup_module(void) { unregister_rule_matching(); IP_RULE_MSG("RULE MATCHING MODULE REMOVED\n"); }