/* *=========================================================================== * ipnet_nat_proxy_h225_msg *=========================================================================== * Description: Track H.225 packets. * This function handles the H.225/Q.931 call signalling packets. NAT calls * this function after translating the address and port number in the IP and * TCP headers, and when the source or destination port is the H.323 port * registered to NAT during the H.323 ALG registration (the standard port for * H.323 protocol is 1720). The H.225 call signalling protocol is used in H.323 * to establish connection between two end-points. * * This function must look at both an outbound as well as an inbound packet. * H.323 connection can be attempted from local to global endpoint or vice * versa. * * NOTE 1: * The fields in the H.225 message are ASN.1 encoded. However, due to schedule, * constraint, rather than employing an ASN.1 decoder, this function uses a simple * strategy to look for the ip+port address in the H.225 payload by taking advantage * of the fact that the port number always follows immediately after the ip address. * Since the ALG can get the expected ip address from NAT, it can search byte by * byte for this ip address to locate where it is in the H.225 payload.. * * Local host (L) <---------------> NAT <----------------> Global host (G) * * The tuple of IP address and TCP/UDP port number is sometimes called transport * address in some publications, and the same terminology will be used here. * * Case 1: Local (L) endpoint to global (G) endpoint connection * * L starts a TCP connection to G and the H.225 call signaling session starts. * The establishment of this TCP connection is all handled by NAT, so by now, * NAT should have the bind entry for this connection. During the H.225 session, * L will embed its sourceCallSignalAddress (ip/port) and G's transport address * in the H.225 payload to G. Thus, this function must parse for each H.225 * outbound packet, look for L's transport address, and substitute it with the * translated address obtained from NAT. * * In addition, this function must also observe the H.225 inbound packets from G * to look for the H.245 transport address (ip/port) in the connect message from * G. The port number provided by G here will serve as the H.245 port number. * L will use this port number to open the H.245 TCP connection with G. So upon * obtaining the H.245 port number, this function must also register the H.245 * ALG agent to NAT . * * Case 2: Global (G) endpoint to local (L) endpoint connection * * G starts a TCP connection to L via the NAT's H.323 static entry and the H.225 * call signaling session starts. As in case 1, the establishment of this TCP * connection is all handled by NAT, so by now, NAT should have the bind entry * for this connection. During the H.225 session, G will embed its sourceCall- * SignalAddress and L's global transport address in the H.225 payload. So, this * function must examine all inbound H.225 packets and substitute L's global * transport address with its real transport address. * * In addition, this function must also observe the H.225 outbound packets * to look for L's H.245 transport address which is embedded in the connect * message from L to G. The port number embedded in this message will serve as * the H.245 port number. * * G will use this port number to open the H.245 TCP connection with L. So, this * function must also register the H.245 ALG agent to NAT upon obtaining the * H.245 port number. Furthermore, since the H.245 TCP connection will be * started from G to L, this function must create a new TCP bind entry for the * impending H.245 port connection. * * NOTE 2: * TCP sequence adjustment is not required since it is a binary substitution of * IP address and port number in the payload. However, the checksum in the TCP * header must be adjusted when the TCP payload is modified. * * Parameters: appdata - pointer to application data. * applen - pointer to length of application data. * param - pointer to proxy parameters. * Returns: 1 = Packet modified. * 0 = Packet untouched. * -1 = Drop packet. */ IP_STATIC int ipnet_nat_proxy_h225_msg(Ip_u8 *appdata, int applen, Ipnet_nat_proxy_param *param) { Ipnet_nat_proxy_tuple proxy_tuple; Ip_u8 *data, *data_start; Ip_u16 local_port, port; Ip_u32 remote_address, local_address, ip_addr; int data_length, tmp; Ip_bool mod = IP_FALSE; data_length = applen; /* length of TCP payload */ if (data_length <= 0) { /* no payload to look at */ return 0; } /* go to start of TCP payload */ data = appdata; data_start = data; local_address = param->tuple.private_addr; local_port = param->tuple.private_port; remote_address = param->tuple.public_addr; if (param->incoming == IP_FALSE) /* outbound packet */ { /* get the H.225 TCP bind descriptor using L's translated source transport address from the source address in the TCP/IP header. From the bind descriptor, obtain L's real transport address and the session flow (i.e. who starts the connection first) of this connection. */ if (param->inbound == IP_FALSE) /* session started by L */ { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_h225_msg() :: outbound packet, outbound session. " "Look for sourceCallSignalAddress from local host."); while ((data + 6) <= (data_start + data_length)) { ip_addr = IP_GET_NTOHL(data); /* look for L's sourceCallSignalAddress match */ if (ip_addr == local_address) { port = IP_GET_NTOHS(data + 4); if (port == local_port) { /* replace with L's translated sourceCallSignalAdress */ IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "Replace local address and port (0x%08x:%d) in H225 payload.", ip_addr, port); IP_SET_HTONL(data, param->nat_addr); IP_SET_HTONS(data + 4, param->nat_port); data += 6; mod = IP_TRUE; IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "Translated local address and port are (0x%08x:%d)", param->nat_addr, param->nat_port); } else /* port != bind_info.local_transport */ { data++; IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_h225_msg() :: matched local address found, " "but not the port number."); } } else /* ip_addr != bind_info.local_addr */ { data++; } } } else /* session started by G */ { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_h225_msg() :: outbound packet, inbound session. " "Look for H245Address from local host."); while ((data + 6) <= (data_start + data_length)) { ip_addr = IP_GET_NTOHL(data); /* look for L's H245Address port */ if (ip_addr == local_address) { port = IP_GET_NTOHS(data + 4); IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "Found H245Address (0x%08x:%d) in H225 payload.", ip_addr, port); /* register H.245 ALG to NAT */ /* if NAPT, create a H.245 TCP bind entry to prepare for H.245 connection request from G */ ipcom_memset(&proxy_tuple, 0, sizeof(proxy_tuple)); proxy_tuple.protocol = param->tuple.protocol; proxy_tuple.private_addr = local_address; proxy_tuple.private_port = port; proxy_tuple.public_addr = remote_address; tmp = ipnet_nat_proxy_add_mapping(&proxy_tuple, 0, param->mapping, IP_TRUE, /* Use port translation */ IP_TRUE, /* Inbound session */ ipnet_nat_proxy_h245, IP_NULL); if (tmp < 0) { IPCOM_LOG2(ERR, "ipnet_nat_proxy_h225_msg() :: Failed to add mapping for address = 0x%08x, port = %d", local_address, port); } else { IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: Added mapping for address = 0x%08x, port = %d", local_address, port); } IP_SET_HTONL(data, param->nat_addr); IP_SET_HTONS(data + 4, (Ip_u16)tmp); data += 6; mod = IP_TRUE; IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "Translated local address and port are (0x%08x:%d)", param->nat_addr, tmp); } else /* ip_addr != bind_info.local_addr */ { data++; } }/* while */ } /* else: session started by G */ } else /* inbound packet */ { if (param->inbound == IP_FALSE) /* session started by L */ { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_h225_msg() :: inbound packet, outbound session. " "Look for H245Address from remote host."); while ((data + 6) <= (data_start + data_length)) { ip_addr = IP_GET_NTOHL(data); /* look for G's H245Address match */ if (ip_addr == remote_address) { port = IP_GET_NTOHS(data + 4); IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "H245Address from remote host found (0x%08x:%d).", ip_addr, port); /* register H.245 ALG to NAT */ ipcom_memset(&proxy_tuple, 0, sizeof(proxy_tuple)); proxy_tuple.protocol = param->tuple.protocol; proxy_tuple.public_addr = ip_addr; proxy_tuple.public_port = port; proxy_tuple.private_addr = param->tuple.private_addr; if (ipnet_nat_proxy_add_mapping(&proxy_tuple, 0, param->mapping, IP_TRUE, /* Use port translation */ IP_FALSE, /* Outbound session */ ipnet_nat_proxy_h245, IP_NULL) < 0) { IPCOM_LOG2(ERR, "ipnet_nat_proxy_h225_msg() :: Failed to add mapping for address = 0x%08x, port = %d", remote_address, port); } else { IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: Added mapping for address = 0x%08x, port = %d", remote_address, port); } } data++; } } else /* session started by G */ { /* search for L's transport address in the H225 payload. If found, translate it to its real transport address. */ IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_h225_msg() :: inbound packet, inbound session." "Translate global transport to its local transport."); while ((data + 6) <= (data_start + data_length)) { ip_addr = IP_GET_NTOHL(data); /* look for L's translated address match */ if (ip_addr == param->nat_addr) { port = IP_GET_NTOHS(data + 4); IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "global ip match found in H.225 payload (0x%08x:%d).", ip_addr, port); if (port == param->nat_port) { IP_SET_HTONL(data, local_address); IP_SET_HTONS(data + 4, local_port); data += 6; mod = IP_TRUE; IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h225_msg() :: " "After translation local_address and port are (0x%08x:%d).", local_address, local_port); } else /* port != bind_info.global_transport */ { data++; } } else /* ip_addr != bind_info.global_addr */ { data++; } } /* while */ } /* else (session started by G) */ } return mod == IP_TRUE ? 1 : 0; }
/* *=========================================================================== * ipnet_nat_proxy_dns_parse_answers *=========================================================================== * Description: Parses and modifies DNS answers in a DNS packet. * Parameters: buf - pointer to buffer with the DNS questions. * buflen - length of buffer with DNS questions. * offset - offset in the buffer where the DNS questions begin. * newlen - pointer to the length of the message if modified. * dns_hdr - pointer to the DNS protocol header. * param - pointer to NAT proxy parameters. * Returns: The number of bytes parsed or -1 if failed. */ IP_STATIC Ip_s32 ipnet_nat_proxy_dns_parse_answers(Ip_u8 *buf, int buflen, int offset, int *newlen, Ipnet_nat_dns_hdr *dns_hdr, Ipnet_nat_proxy_param *param) { int i, count, origoffset, numa; Ip_u16 type, cla, rlen; int newbuflen = sizeof(dnsbuf); Ipnet_nat_dns_transaction *trans; numa = IP_GET_NTOHS(&dns_hdr->no_answ); origoffset = offset; for (i=0; i<numa; i++) { /* Get the name */ count = ipnet_nat_proxy_dns_decode_name(buf, buflen, offset, dnsname, sizeof(dnsname)); if (count < 0) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: could not decode dns name"); return -1; } /* Copy the name */ if (newbuflen - *newlen < count) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } ipcom_memcpy(&dnsbuf[*newlen], buf+offset, count); *newlen += count; offset += count; /* Check space for type, class, ttl and record length */ if (buflen - offset < 10) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: message too short to parse answer"); return -1; } /* Get the type */ type = (Ip_u16)(IP_GET_NTOHS(buf+offset)); switch(type) { case IPNET_NAT_DNS_QTYPE_A: type = IPNET_NAT_DNS_QTYPE_AAAA; break; case IPNET_NAT_DNS_QTYPE_PTR: trans = ipnet_nat_proxy_dns_find_transaction(IPNET_NAT_DNS_QTYPE_PTR, dns_hdr, param); if (trans != IP_NULL) { IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_dns_parse_answers() :: found transaction:" "id=%d port=%d addr=0x%08x type=%d", trans->id, trans->srcport, trans->dstaddr, trans->type); *newlen -= count; /* Move index back to before the name */ count = ipnet_nat_proxy_dns_encode_name(dnsbuf, newbuflen, *newlen, trans->ptrname); if (count < 0) { ipnet_nat_proxy_dns_remove_transaction(trans); IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: could not encode dns name"); return -1; } *newlen += count; if (i+1 == numa) { /* Remove transaction for last answer */ ipnet_nat_proxy_dns_remove_transaction(trans); } } break; default: break; } /* Copy the type */ if (newbuflen - *newlen < 2) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } IP_SET_HTONS(&dnsbuf[*newlen], type); *newlen += 2; offset += 2; /* Get the class */ cla = (Ip_u16)(IP_GET_NTOHS(buf+offset)); if (cla != IPNET_NAT_DNS_QCLASS_INET) { IPCOM_LOG1(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: unhandled class: %d", cla); return -1; } /* Copy the class */ if (newbuflen - *newlen < 2) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } IP_SET_HTONS(&dnsbuf[*newlen], cla); *newlen += 2; offset += 2; /* Copy the ttl */ if (newbuflen - *newlen < 4) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } ipcom_memcpy(&dnsbuf[*newlen], buf+offset, 4); *newlen += 4; offset += 4; /* Get the record length */ rlen = (Ip_u16)(IP_GET_NTOHS(buf+offset)); if (buflen - offset < rlen) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: message too short to parse answer"); return -1; } /* Copy the record length */ if (newbuflen - *newlen < 2) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } if (type == IPNET_NAT_DNS_QTYPE_AAAA && rlen == 4) { /* Modify record length and make space for the AAAA record */ IP_SET_HTONS(&dnsbuf[*newlen], 16); *newlen += 2; /* Insert AAAA record data */ if (newbuflen - *newlen < 12) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } ipcom_memcpy(&dnsbuf[*newlen], param->prefix, 12); *newlen += 12; } else { IP_SET_HTONS(&dnsbuf[*newlen], rlen); *newlen += 2; } offset += 2; /* Copy the record */ if (newbuflen - *newlen < rlen) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer"); return -1; } ipcom_memcpy(&dnsbuf[*newlen], buf+offset, rlen); *newlen += rlen; offset += rlen; } return offset - origoffset; }
/* *=========================================================================== * ipnet_nat_proxy_dns_reply *=========================================================================== * Description: Parse and modify DNS reply. * Parameters: appdata - pointer to application data. * applen - pointer to length of application data. * growspace - space available to extend application data. * param - pointer to proxy parameters. * newdata - pointer to pointer to new application data. * Returns: 1 = Packet modified. * 0 = Packet untouched. */ IP_STATIC int ipnet_nat_proxy_dns_reply(Ip_u8 *appdata, int *applen, int growspace, Ipnet_nat_proxy_param *param, Ip_u8 **newdata) { Ipnet_nat_dns_hdr *dns_hdr; Ip_u16 flags; int offset, diff, qlen; int newbuflen = sizeof(dnsbuf); int newlen = 0; /* Check that at least a header is included */ if (*applen < (int)sizeof(*dns_hdr)) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_reply() :: message too short for dns header"); return 0; } dns_hdr = (Ipnet_nat_dns_hdr *)appdata; flags = IP_GET_NTOHS(&dns_hdr->flags); if((flags & IPNET_NAT_DNS_QR_FLAG) != IPNET_NAT_DNS_QR_FLAG || /* Not a reply */ (flags & IPNET_NAT_DNS_OPCODE_FLAG) != 0 || /* Not a standard query */ (flags & IPNET_NAT_DNS_TC_FLAG) != 0) /* Truncated */ { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_reply() :: invalid header"); return 0; } /* Copy the header */ if (newbuflen - newlen < (int)sizeof(*dns_hdr)) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_reply() :: no space left in modified buffer"); return 0; } ipcom_memcpy(&dnsbuf[newlen], dns_hdr, sizeof(*dns_hdr)); newlen += sizeof(*dns_hdr); /* Get the questions */ offset = sizeof(*dns_hdr); qlen = ipnet_nat_proxy_dns_parse_questions(appdata, *applen, offset, &newlen, dns_hdr, param); if (qlen < 0) return 0; offset += qlen; /* Get the answers */ qlen = ipnet_nat_proxy_dns_parse_answers(appdata, *applen, offset, &newlen, dns_hdr, param); if (qlen < 0) return 0; offset += qlen; /* Skip authority and additional records */ dns_hdr = (Ipnet_nat_dns_hdr *)&dnsbuf[0]; IP_SET_HTONS(&dns_hdr->no_auth, 0); IP_SET_HTONS(&dns_hdr->no_addi, 0); /* Update application data with the modified buffer */ diff = newlen - *applen; if (diff > growspace) { /* Must allocate a new buffer */ *newdata = ipcom_malloc(*applen + diff); if (*newdata == IP_NULL) { IPCOM_LOG1(ERR, "ipnet_nat_proxy_dns_reply() :: ipcom_malloc(%d) failed", *applen + diff); return -1; } ipcom_memcpy(*newdata, dnsbuf, newlen); } else { /* Let the current buffer grow */ ipcom_memcpy(appdata, dnsbuf, newlen); } *applen = newlen; return 1; }
/* *=========================================================================== * ipnet_nat_proxy_dns_parse_questions *=========================================================================== * Description: Parses and modifies DNS questions in a DNS packet. * Parameters: buf - pointer to buffer with the DNS questions. * buflen - length of buffer with DNS questions. * offset - offset in the buffer where the DNS questions begin. * newlen - pointer to the length of the message if modified. * dns_hdr - pointer to the DNS protocol header. * param - pointer to NAT proxy parameters. * Returns: The number of bytes parsed or -1 if failed. */ IP_STATIC Ip_s32 ipnet_nat_proxy_dns_parse_questions(Ip_u8 *buf, int buflen, int offset, int *newlen, Ipnet_nat_dns_hdr *dns_hdr, Ipnet_nat_proxy_param *param) { int i, j, k, count, origoffset, numq, numa, request; Ip_u16 type, cla, flags; Ip_u8 addr[4]; Ipnet_nat_dns_transaction *trans; int newbuflen = sizeof(dnsbuf); Ip_u8 c, *zone; numq = IP_GET_NTOHS(&dns_hdr->no_ques); if (numq != 1) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: supports only one question per message"); return -1; } numa = IP_GET_NTOHS(&dns_hdr->no_answ); flags = IP_GET_NTOHS(&dns_hdr->flags); request = (flags & IPNET_NAT_DNS_QR_FLAG) != 0 ? 0 : 1; origoffset = offset; for (i=0; i<numq; i++) { /* Get the name */ count = ipnet_nat_proxy_dns_decode_name(buf, buflen, offset, dnsname, sizeof(dnsname)); if (count < 0) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: could not decode dns name"); return -1; } /* Copy the name */ if (newbuflen - *newlen < count) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: no space left in modified buffer"); return -1; } ipcom_memcpy(&dnsbuf[*newlen], buf+offset, count); *newlen += count; offset += count; /* Check space for type and class */ if (buflen - offset < 4) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: message too short to parse question"); return -1; } /* Get the type */ type = (Ip_u16)(IP_GET_NTOHS(buf+offset)); switch(type) { case IPNET_NAT_DNS_QTYPE_AAAA: if (request) { trans = ipnet_nat_proxy_dns_add_transaction(IPNET_NAT_DNS_QTYPE_A, dns_hdr, param, IP_NULL); if (trans == IP_NULL) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_dns_parse_questions() :: could not add transaction to list"); return -1; } else { IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_dns_parse_questions() :: added transaction:" "id=%d port=%d addr=0x%08x type=%d", trans->id, trans->srcport, trans->dstaddr, trans->type); } type = IPNET_NAT_DNS_QTYPE_A; /* Change type to A */ } break; case IPNET_NAT_DNS_QTYPE_A: if (!request) { trans = ipnet_nat_proxy_dns_find_transaction(IPNET_NAT_DNS_QTYPE_A, dns_hdr, param); if (trans != IP_NULL) { IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_dns_parse_questions() :: found transaction:" "id=%d port=%d addr=0x%08x type=%d", trans->id, trans->srcport, trans->dstaddr, trans->type); ipnet_nat_proxy_dns_remove_transaction(trans); } else { return -1; } type = IPNET_NAT_DNS_QTYPE_AAAA; /* Change type back to AAAA */ } break; case IPNET_NAT_DNS_QTYPE_PTR: if (request) { zone = (Ip_u8 *)ipcom_strstr((char *)dnsname, "ip6.int"); if (zone == IP_NULL) zone = (Ip_u8 *)ipcom_strstr((char *)dnsname, "ip6.arpa"); if (zone == IP_NULL) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_dns_parse_questions() :: unhandled zone in PTR request"); return -1; } /* Extract IPv4 part */ if (ipcom_strlen((char *)dnsname) != 64 + ipcom_strlen((char *)zone)) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: invalid name in PTR request"); return -1; } k=0; for (j=3; j>=0; j--) { c = ipcom_tolower(dnsname[k]); c = c > '9' ? c - 'a' + 10 : c - '0'; addr[j] = c; k += 2; c = ipcom_tolower(dnsname[k]); c = c > '9' ? c - 'a' + 10 : c - '0'; c <<= 4; addr[j] += c; k += 2; } trans = ipnet_nat_proxy_dns_add_transaction(IPNET_NAT_DNS_QTYPE_PTR, dns_hdr, param, dnsname); if (trans == IP_NULL) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_dns_parse_questions() :: could not add transaction to list"); return -1; } else { IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_dns_parse_questions() :: added transaction:" "id=%d port=%d addr=0x%08x type=%d", trans->id, trans->srcport, trans->dstaddr, trans->type); } /* Convert address to PTR name */ if (ipnet_nat_proxy_dns_ptr_name(dnsname, sizeof(dnsname), addr, IP_AF_INET, (Ip_u8 *)"in-addr.arpa") < 0) { ipnet_nat_proxy_dns_remove_transaction(trans); IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: could not encode PTR name"); return -1; } *newlen -= count; /* Move index back to before the name */ count = ipnet_nat_proxy_dns_encode_name(dnsbuf, newbuflen, *newlen, dnsname); if (count < 0) { ipnet_nat_proxy_dns_remove_transaction(trans); IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: could not encode dns name"); return -1; } *newlen += count; } else { trans = ipnet_nat_proxy_dns_find_transaction(IPNET_NAT_DNS_QTYPE_PTR, dns_hdr, param); if (trans != IP_NULL) { IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_dns_parse_questions() :: found transaction:" "id=%d port=%d addr=0x%08x type=%d", trans->id, trans->srcport, trans->dstaddr, trans->type); *newlen -= count; /* Move index back to before the name */ count = ipnet_nat_proxy_dns_encode_name(dnsbuf, newbuflen, *newlen, trans->ptrname); if (count < 0) { ipnet_nat_proxy_dns_remove_transaction(trans); IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: could not encode dns name"); return -1; } *newlen += count; if (numa == 0) { /* Remove the transaction if there are no answers */ ipnet_nat_proxy_dns_remove_transaction(trans); } } else { return -1; } } break; default: return -1; } /* Copy the type */ if (newbuflen - *newlen < 2) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: no space left in modified buffer"); return -1; } IP_SET_HTONS(&dnsbuf[*newlen], type); *newlen += 2; offset += 2; /* Get the class */ cla = (Ip_u16)(IP_GET_NTOHS(buf+offset)); if (cla != IPNET_NAT_DNS_QCLASS_INET) { IPCOM_LOG1(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: unhandled class: %d", cla); return -1; } /* Copy the class */ if (newbuflen - *newlen < 2) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: no space left in modified buffer"); return -1; } IP_SET_HTONS(&dnsbuf[*newlen], cla); *newlen += 2; offset += 2; } return offset - origoffset; }