/* *=========================================================================== * ipnet_config_add_inet_addr *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_config_add_inet_addr(Ip_fd fd, char *ifname, char *option) { char *inet_addr; char *prefix_len; char *argv[] = { "ifconfig", "-silent", IP_NULL, "inet", "add", IP_NULL, IP_NULL, IP_NULL, IP_NULL }; int argc = 5; char inet_addr_str[IP_INET_ADDRSTRLEN]; char inet_prefix_len_str[8]; argv[2] = ifname; inet_addr = ipcom_strtok_r(option, " \t/", &option); if (inet_addr == IP_NULL) { IPCOM_LOG0(ERR, "inet address is missing or format is invalid"); return -IP_ERRNO_EINVAL; } if (ipcom_strcmp(inet_addr, "dhcp") == 0) { struct Ip_ifreq ifreq; use_dhcp: ipcom_strcpy(ifreq.ifr_name, ifname); ifreq.ifr_ifru.ifru_opt = 1; if (ipcom_socketioctl(fd, IP_SIOCXSDHCPRUNNING, &ifreq) < 0) { IPCOM_LOG1(ERR, "Failed to enable DHCP on %s", ifname); return ipcom_errno; } return 0; } #ifdef IPNET_USE_RARP if (ipcom_strcmp(inet_addr, "rarp") == 0) { struct Ip_ethreq ethreq; ipcom_strcpy(ethreq.ethr_name, ifname); ethreq.ethru.rarp = -1; if (ipcom_socketioctl(fd, IP_SIOCXETHSRARP, ðreq) < 0) { IPCOM_LOG1(ERR, "Failed to enable RARPP on %s", ifname); return ipcom_errno; } return 0; } #endif /* IPNET_USE_RARP */ if (ipcom_strcmp(inet_addr, "driver") == 0) { /* Get the IPv4 address to use from the driver */ struct Ip_ethreq ethreq; ipcom_strcpy(ethreq.ethr_name, ifname); if (ipcom_socketioctl(fd, IP_SIOCXETHGINET, ðreq) < 0) { IPCOM_LOG1(ERR, "Failed to read the IPv4 address from the driver for %s", ifname); return ipcom_errno; } if (ethreq.ethru.inet.addr.s_addr == 0xffffffff) goto use_dhcp; inet_addr = inet_addr_str; (void) ipcom_inet_ntop(IP_AF_INET, ðreq.ethru.inet.addr, inet_addr_str, sizeof(inet_addr_str)); prefix_len = inet_prefix_len_str; ipcom_snprintf(inet_prefix_len_str, sizeof(inet_prefix_len_str), "%d", ipcom_mask_to_prefixlen(ðreq.ethru.inet.mask, 32)); } else { prefix_len = ipcom_strtok_r(option, " \t/", &option); if (prefix_len == IP_NULL) { IPCOM_LOG0(ERR, "prefix len is missing or format is invalid"); return -IP_ERRNO_EINVAL; } } argv[argc++] = inet_addr; argv[argc++] = "prefixlen"; argv[argc++] = prefix_len; return ipnet_config_cmd_ifconfig(argc, argv); }
/* *=========================================================================== * ipcom_buffer_new *=========================================================================== * Description: * Parameters: * Returns: * */ Ipcom_buffer* ipcom_buffer_new(Ip_s32 size) { Ipcom_buffer *buffer; buffer = ipcom_malloc(sizeof(Ipcom_buffer)); if(!buffer) { IPCOM_LOG0(ERR, "ipcom_buffer_new() :: out of memory"); return IP_NULL; } buffer->buf = ipcom_malloc(size); if(buffer->buf == IP_NULL) { IPCOM_LOG0(ERR, "ipcom_buffer_new() :: out of memory"); ipcom_free(buffer); return IP_NULL; } buffer->alloc = size; buffer->offset = 0; buffer->end = 0; #ifdef IP_DEBUG ipcom_memset(buffer->buf, 0xcc, size); #endif return buffer; }
/* *=========================================================================== * ipcom_egd *=========================================================================== * Description: This process gathers random data by calling ipcom_random_bingo_lotto() * * Applications can access the random data before the full entropy * has been gathered. This will of course mean that the quality of * the random data will not be as good, but in some situations that * may be a better trade-off than no random data at all. * Parameters: * Returns: * */ IP_STATIC IPCOM_PROCESS(ipcom_egd) { Ipcom_egd_hash_ctx md5_ctx; Ipcom_egd_hash_ctx tmp_md5_ctx; Ip_s32 rnd; Ipcom_tmo tmo; #ifdef IPCOM_EGD_DEBUG int i; #endif ipcom_proc_init(); IPCOM_LOG0(DEBUG, "ipcom_egd :: starting"); ipcom_egd_hash_init(&md5_ctx); ipcom_egd_laps = 0; #ifdef IPCOM_EGD_DEBUG ipcom_memset(ipcom_egd_raw_data, 0, sizeof(ipcom_egd_raw_data)); #endif while(ipcom_egd_laps < IPCOM_RANDOM_LAPS) { ipcom_egd_tmo_flag = 0; if(ipcom_tmo_request(&tmo, ipcom_random_tmo_handler, (int*)&ipcom_egd_tmo_flag, 50) != IPCOM_SUCCESS) { IPCOM_LOG0(ERR, "ipcom_egd :: timeout request failed, seed aborted"); goto exit; } rnd = ipcom_random_bingo_lotto(); #ifdef IPCOM_EGD_DEBUG ipcom_egd_raw_data[ipcom_egd_laps] = rnd; #endif ipcom_egd_hash_update(&md5_ctx, (void*) &rnd, sizeof(Ip_u32)); ipcom_memcpy(&tmp_md5_ctx, &md5_ctx, sizeof(Ipcom_egd_hash_ctx)); ipcom_egd_hash_final(ipcom_random_state, &tmp_md5_ctx); ipcom_egd_laps++; ipcom_millisleep(IPCOM_EGD_SLEEP_TIME); } exit: #ifdef IPCOM_EGD_DEBUG for (i=0; i < ipcom_egd_laps; i++) { IPCOM_LOG2(INFO, "ipcom_egd_raw_data[%d] = %d", i, ipcom_egd_raw_data[i]); ipcom_millisleep(100); } #endif IPCOM_LOG0(DEBUG, "ipcom_egd :: terminating"); ipcom_proc_exit(); }
/* *=========================================================================== * ipnet_pkt_queue_mbc_configure *=========================================================================== * Description: Configures a queue with new parameters. * Parameters: q - A packet queue. * m - The queue parameters. * Returns: 0 = success * <0 = error code */ IP_STATIC int ipnet_pkt_queue_mbc_configure(Ipnet_pkt_queue_mbc *q, struct Ipnet_ifqueue_mbc *m) { Ip_u32 band; if (q->number_of_bands) { IPCOM_LOG0(ERR, "MBC configure: Can only be configured once"); return -IP_ERRNO_EINVAL; } if (m->mbc_bands < 2 || m->mbc_bands > IPNET_IFQ_CONTAINER_MAX_COUNT) { IPCOM_LOG1(ERR, "MBC configure: Number of priority bands must be between 2 and %d", IPNET_IFQ_CONTAINER_MAX_COUNT); return -IP_ERRNO_EINVAL; } if (m->mbc_bands <= m->mbc_default_band) { IPCOM_LOG1(ERR, "MBC configure: invalid default band, must be [0..%d]", m->mbc_bands - 1); return -IP_ERRNO_EINVAL; } q->bands = ipcom_calloc(m->mbc_bands, sizeof(Ipnet_pkt_queue *)); if (q->bands == IP_NULL) { IPCOM_LOG0(CRIT, "MBC configure: out of memory"); return -IP_ERRNO_ENOMEM; } q->number_of_bands = m->mbc_bands; q->default_band = m->mbc_default_band; for (band = 0; band < q->number_of_bands; band++) { int ret; ret = ipnet_pkt_queue_mbc_insert_default_queue(q, band); if (ret < 0) { IPCOM_LOG1(ERR, "MBC configure: Failed to create default queue: %s", ipcom_strerror(-ret)); return ret; } } return 0; }
/* *=========================================================================== * ipnet_nat_proxy_sip_callidstr *=========================================================================== * Description: Extract the callid string * Parameters: pdata - pointer to message. * Returns: pointer to allocated buffer with callid string or * IP_NULL if wrong format or out of memory. */ IP_STATIC char * ipnet_nat_proxy_sip_callidstr(char *pmsg) { char *pstart; char *pcallid; int i; SIP_SKIP_SPACES(pmsg); pstart = pmsg; for (i = 0; i < 200; i++) { if (*pmsg != '\r') pmsg++; else break; } /* in case we have a wrong string format */ if (i >= 200) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_callidstr() :: ERROR, wrong string format"); return IP_NULL; } if ((pcallid = ipcom_malloc((pmsg - pstart) + 1)) == IP_NULL) return IP_NULL; ipcom_memcpy(pcallid, pstart, pmsg - pstart); *(pcallid + (pmsg - pstart)) = 0; IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_callidstr() :: callid=%s", pcallid); return pcallid; }
/* *=========================================================================== * ipnet_nat_proxy_sip_msg *=========================================================================== * Description: Track SIP packets. * 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. * -1 = Drop packet. */ IP_STATIC int ipnet_nat_proxy_sip_msg(Ip_u8 *appdata, int *applen, int growspace, Ipnet_nat_proxy_param *param, Ip_u8 **newdata) { Ip_bool status; int ret = 1; IPCOM_LOG5(DEBUG, "ipnet_nat_proxy_sip_msg(%s:%s) :: BEGIN public=0x%x, private=0x%x len=%d", param->incoming == IP_TRUE ? "INCOMING" : "OUTGOING", param->inbound == IP_TRUE ? "INBOUND" : "OUTBOUND", param->tuple.public_addr, param->tuple.private_addr, *applen); /* Inspect the payload */ status = ipnet_nat_proxy_sip_payload_parse(appdata, applen, growspace, param, newdata); if (status == IP_FALSE) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_msg() :: message header did not match, no translation"); ret = 0; } IPCOM_LOG5(DEBUG, "ipnet_nat_proxy_sip_msg(%s:%s) :: END public=0x%x, private=0x%x len=%d", param->incoming == IP_TRUE ? "INCOMING" : "OUTGOING", param->inbound == IP_TRUE ? "INBOUND" : "OUTBOUND", param->tuple.public_addr, param->tuple.private_addr, *applen); return ret; }
/* *=========================================================================== * ipnet_nat_proxy_sip_modmsg *=========================================================================== * Description: Modify message and adjust length * Parameters: newdata - pointer to new data * newlen - length of new data * olddata - pointer to old data * oldlen - length of old data * ppend - pointer to pointer to last byte of message * Returns: 0 = ok * -1 = message too long */ IP_STATIC int ipnet_nat_proxy_sip_modmsg(char *newdata, int newlen, char *olddata, int oldlen, char **ppend) { char *pmax = (char *)sipbuf + sizeof(sipbuf) - 1; int diff = newlen - oldlen; int movelen = (*ppend + 1) - (olddata + oldlen); ip_assert(movelen >= 0); if (pmax - *ppend < diff) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_modmsg() :: message to long"); return -1; } /* Make space for new data */ ipcom_memmove(olddata + newlen, olddata + oldlen, movelen); *ppend += diff; /* Copy in new data */ ipcom_memcpy(olddata, newdata, newlen); return 0; }
/* *=========================================================================== * ipnet_nat_proxy_sip_addrportstrparse *=========================================================================== * Description: Parse the address/port string * This routine parses a combination of address and port string. * The address part can be terminated by ':', '\r' or '>' * characters. * Parameters: pstr - pointer to message * pipaddr - buffer for parsed IP address * pport - buffer for parsed port * type - type of search * Returns: The next character position after the parsed string or * IP_NULL if parse fails */ IP_STATIC char * ipnet_nat_proxy_sip_addrportstrparse(char *pstr, Ip_u32 *pipaddr, int *pport, int type) { int i; char *pend; Ip_bool noport = IP_FALSE; char tmpholder[20]; if (type == SIP_ADDRESS_PORT_STRING) { for (i = 0; i < 20; i++) { if (pstr[i] == ':' || pstr[i] == '\r' || pstr[i] == '>') break; else tmpholder[i] = pstr[i]; } if (i >= 20 || i == 0) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: ERROR: invalid string"); return IP_NULL; } /* If the address terminated by these characters, then the parsed * string is considered to contain only the address informantion. */ if (pstr[i] == '\r' || pstr[i] == '>') noport = IP_TRUE; tmpholder[i] = 0; *pipaddr = ipcom_inet_addr(tmpholder); if (*pipaddr == IP_INADDR_NONE) return IP_NULL; *pipaddr = ip_ntohl(*pipaddr); pstr += i; } if (type == SIP_PORT_STRING || (type == SIP_ADDRESS_PORT_STRING && noport == IP_FALSE)) { if (type == SIP_ADDRESS_PORT_STRING) pstr++; /* find the port number */ *pport = ipcom_strtol(pstr, &pend, 10); pstr = pend; } else *pport = 0; return pstr; }
/* *=========================================================================== * ipnet_radvd_start *=========================================================================== * Description: Starts the daemon. * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipnet_radvd_start(void) { #ifdef IPNET_USE_RFC3971 Ip_u32 stacksize = IPCOM_PROC_STACK_LARGE; #else Ip_u32 stacksize = IPCOM_PROC_STACK_DEFAULT; #endif IPCOM_LOG0(DEBUG2, "radvd: Start"); return ipcom_proc_create("ipnet_radvd", (Ipcom_proc_func)ipnet_radvd_proc, stacksize, IP_NULL); }
/* *=========================================================================== * ipnet_pkt_queue_mbc_init *=========================================================================== * Description: Configures a queue with new parameters. * Parameters: q - A packet queue. * Returns: * */ IP_STATIC int ipnet_pkt_queue_mbc_init(Ipnet_pkt_queue_mbc *q) { ipcom_memset((Ip_u8 *) q + sizeof(Ipnet_pkt_queue), 0, sizeof(Ipnet_pkt_queue_mbc) - sizeof(Ipnet_pkt_queue)); q->classifier = ipnet_classifier_new(); if (q->classifier == IP_NULL) { IPCOM_LOG0(ERR, "MBC init: Failed to create classifier: out of memory"); return -IP_ERRNO_ENOMEM; } return 0; }
/* *=========================================================================== * ipnet_sock_sockdev_register *=========================================================================== * Description: Registers the IP_AF_SOCKDEV domain. * Parameters: * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int ipnet_sock_sockdev_register(void) { Ipnet_sock_ops *ops; ops = ipcom_calloc(1, sizeof(*ops)); if (ops == IP_NULL) { IPCOM_LOG0(CRIT, "Could not register the IP_AF_SOCKDEV domain, out of memory"); IP_PANIC(); return -IP_ERRNO_ENOMEM; } ops->domain = IP_AF_SOCKDEV; ops->type = IP_SOCK_RAW; ops->proto = -1; ops->destroy = ipnet_sockdev_destroy; ops->init = ipnet_sockdev_init; ops->recv = ipnet_sock_pkt_recv; ops->send = ipnet_sockdev_send; return ipnet_sock_register_ops(ops); }
/* *=========================================================================== * ipnet_gre_setup *=========================================================================== * Description: Setup the GRE tunnel. * Parameters: netif - A GRE tunnel interface. * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int ipnet_gre_setup(Ipnet_netif *netif) { #ifdef IPNET_USE_RFC2890 Ipnet_gre_t *gre; gre = netif->ipcom.pdrv = ipcom_calloc(1, sizeof(Ipnet_gre_t)); if (gre == IP_NULL) goto errout; gre->reassembly_queue = ipcom_pqueue_new((Ipcom_pqueue_cmp_func) ipnet_gre_seq_cmp, ipcom_pqueue_nop_store_index); return 0; errout: ipnet_gre_destroy(netif); IPCOM_LOG0(CRIT, "Failed to create GRE tunnel due to unsifficient memory"); return -IP_ERRNO_ENOMEM; #else IPCOM_UNUSED_ARG(netif); return 0; #endif /* IPNET_USE_RFC2890 */ }
/* *=========================================================================== * ipcom_shell_run_extcmd *=========================================================================== * Description: Starts a shell command process and delivers the command arguments * and stdio socket to that process. * Parameters: argc, argv - traditional command arguments * stdio_fd - the standard input, output and error sock * ppid - parent pid * cmd_pid - shell command process id * * Returns: 1 : command process started * 0 : not an external command * -1 : error * */ IP_PUBLIC Ip_err ipcom_shell_run_extcmd(int argc, char **argv, Ip_fd *stdio_fd, Ip_pid_t ppid, Ip_u32 seqno, Ip_pid_t *cmd_pid, int *proc_index) { Ipcom_proc_attr attr; Ipcom_ipc ipc; Ipcom_shellcmd_info *sinfo; Ipcom_shell_cmd *cmd = IP_NULL; Ipcom_shell_cmd *tcmd; Ip_err retval; char procname[40]; Ip_u32 stack = IPCOM_PROC_STACK_DEFAULT; Ip_pid_t pid; pid = ipcom_getpid(); ipcom_sprintf(procname, "ipcom_sc_0x%lx_%d", (Ip_u32)pid, *proc_index); /* Find command and max stack size (since we are reusing the process). */ if (argc > 0) { for (tcmd = IPCOM_LIST_FIRST(&ipcom_shell_cmd_head); tcmd; tcmd = IPCOM_LIST_NEXT(&tcmd->cmd_list)) { stack = (Ip_u32)IP_MAX(stack, tcmd->stack_size); if (cmd == IP_NULL && ipcom_strcmp(tcmd->name, argv[0]) == 0) { cmd = tcmd; if (*cmd_pid != 0) break; } } if (cmd == IP_NULL) return 0; /* Start the shell_cmd process. */ if (*cmd_pid == 0) { ipcom_proc_attr_init(&attr); attr.priority = (Ip_u32)cmd->priority; attr.stacksize = stack; attr.flags |= IPCOM_PROC_FLAG_FP; if (ipcom_proc_acreate(procname, (Ipcom_proc_func)ipcom_shell_cmd, &attr, cmd_pid)) { IPCOM_LOG0(ERR, "ipcom_shell_run_extcmd :: ipcom_proc_acreate() failed"); goto fail; } ip_assert(*cmd_pid != 0); } } else { /* argc == 0 is used to kill the shell_cmd process. */ ip_assert(*cmd_pid != 0); } /* Open IPC with ipcom_shell. */ retval = ipcom_ipc_open(&ipc, procname, -1); if (retval != IPCOM_SUCCESS) { IPCOM_LOG2(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_open(%s) failed, ret = %d", procname, retval); goto fail; } /* Send a message to ipcom_shell. */ sinfo = ipcom_ipc_malloc(sizeof(Ipcom_shellcmd_info)); if (sinfo == IP_NULL) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_malloc() failed, ret = %d", retval); goto fail; } /* Fill in IPC info. */ sinfo->argc = argc; if (argc > 0) { sinfo->hook = cmd->hook; sinfo->argv = argv; sinfo->fd = *stdio_fd; sinfo->pid = pid; sinfo->ppid = ppid; sinfo->seqno = seqno; #if IPCOM_USE_FILE != IPCOM_FILE_NONE if (ipcom_getcwd(sinfo->cwd, sizeof(sinfo->cwd)) == IP_NULL) ipcom_memset(sinfo->cwd, 0, sizeof(sinfo->cwd)); else sinfo->cwd[sizeof(sinfo->cwd)-1] = '\0'; #endif sinfo->prio = cmd->priority; } /* Send the IPC info. */ retval = ipcom_ipc_send(&ipc, sinfo); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_send() failed, ret = %d", retval); ipcom_ipc_free(sinfo); goto fail; } (void)ipcom_ipc_close(&ipc); #ifdef IP_PORT_OSE5 if (argc > 0) { /* OSE5 has process specific sockets -> donate child fd */ ip_assert(*cmd_pid != 0); retval = (Ip_err)efs_donate_fd(*stdio_fd, *cmd_pid); if (retval != 0) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: efs_donate_fd, ret = %d", retval); goto fail; } } #endif /* IP_PORT_OSE5 */ /* Wait for exit message from shell_cmd process. */ retval = ipcom_ipc_receive(IP_NULL, &sinfo, -1); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipcom_shell_run_extcmd :: ipcom_ipc_receive(shell_cmd) failed, ret = %d", retval); goto fail; } ip_assert(argc > 0 || *(Ip_u32 *)sinfo == 1); if (*(Ip_u32 *)sinfo == 1) { *cmd_pid = 0; /* shell command called ipcom_exit(). */ (*proc_index)++; } else { #ifdef IP_PORT_OSE5 *stdio_fd = efs_receive_fd(0); if (*stdio_fd == -1) { IP_PANIC(); goto fail; } #endif #if defined(IP_PORT_OSE) || defined(IP_PORT_OSE5) /* Change child socket owner (A must for OSE to work due to poor ipcom_block impl). */ pid = ipcom_getpid(); if (ipcom_socketioctl(*stdio_fd, IP_SIOCSPGRP, &pid) < 0) { IP_PANIC2(); IPCOM_LOG1(WARNING, "ipcom_shell_run_extcmd :: ipcom_socketioctl(IP_SIOCSPGRP) failed, errno = %d", ipcom_errno); } #endif } ipcom_ipc_free(sinfo); return 1; fail: if (ipcom_ipc_isopen(&ipc)) (void)ipcom_ipc_close(&ipc); return -1; }
/* *=========================================================================== * ipnet_nat_proxy_sip_inboundmsgtypecheck *=========================================================================== * Description: Find the type of inbound SIP message * Parameters: psipmsg - pointer to buffer message * ptype - pointer to buffer for returned status * Returns: Pointer to message after the type or IP_NULL * if type not found. */ IP_STATIC char * ipnet_nat_proxy_sip_inboundmsgtypecheck(char *psipmsg, int *ptype, int searchlen) { int pos; /* check if the first 3 char is "SIP" */ if (SIP_IS_STRING_SAME(psipmsg, SIP_SIP_STR)) { /* yes, it is, check if it is status code 200 */ psipmsg += 8; if (SIP_IS_STRING_SAME(psipmsg, SIP_200_OK_STR)) { /* this is the status 200 OK message */ psipmsg += ipcom_strlen(SIP_200_OK_STR); *ptype = SIP_MSG_TYPE_STATUS; /* check if the INVITE or BYE code */ if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_CSEQ_STR, &pos, searchlen) == IP_TRUE) { char * pbye; pbye = psipmsg + pos + SIP_TAG_TO_DATAPOS(SIP_CSEQ_STR); SIP_SKIP_SPACES(pbye); /* skip the number field */ while (*pbye != ' ') pbye++; SIP_SKIP_SPACES(pbye); if (SIP_IS_STRING_SAME (pbye, SIP_INVITE_STR)) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_inboundmsgtypecheck() :: STATUS(INVITE) message"); *ptype = SIP_MSG_TYPE_INVITE; } else if (SIP_IS_STRING_SAME (pbye, SIP_BYE_STR)) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_inboundmsgtypecheck() :: STATUS(BYE) message"); *ptype = SIP_MSG_TYPE_BYE; } else if (SIP_IS_STRING_SAME (pbye, SIP_CANCEL_STR)) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_inboundmsgtypecheck() :: STATUS(BYE) message"); *ptype = SIP_MSG_TYPE_BYE; } } return psipmsg; } return IP_NULL; } if (SIP_IS_STRING_SAME(psipmsg, SIP_BYE_STR)) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_inboundmsgtypecheck() :: BYE message"); psipmsg += ipcom_strlen(SIP_BYE_STR); *ptype = SIP_MSG_TYPE_BYE; return psipmsg; } else if (SIP_IS_STRING_SAME(psipmsg, SIP_MESSAGE_STR)) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_inboundmsgtypecheck() :: MESSAGE message"); psipmsg += ipcom_strlen(SIP_MESSAGE_STR); *ptype = SIP_MSG_TYPE_MESSAGE; return psipmsg; } return IP_NULL; /* not the SIP messages we want */ }
/* *=========================================================================== * ipnet_sock_udp_register *=========================================================================== * Description: Registers the UDP protocol for IPv4 and/or IPv6. * Parameters: * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int ipnet_sock_udp_register(void) { Ipnet_sock_udp_ops *ops; int domains[] = { #ifdef IPCOM_USE_INET IP_AF_INET, #endif #ifdef IPCOM_USE_INET6 IP_AF_INET6, #endif }; int protos[] = { 0, IP_IPPROTO_UDP }; Ip_size_t d, p; int ret; for (d = 0; d < sizeof(domains) / sizeof(domains[0]); d++) for (p = 0; p < sizeof(protos) / sizeof(protos[0]); p++) { ops = ipcom_calloc(1, sizeof(*ops)); if (ops == IP_NULL) { IPCOM_LOG0(CRIT, "Could not register the UDP protocol, out of memory"); IP_PANIC(); return -IP_ERRNO_ENOMEM; } switch (domains[d]) { #ifdef IPCOM_USE_INET case IP_AF_INET: ipnet_sock_ip4_get_ops(&ops->inet); break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: ipnet_sock_ip6_get_ops(&ops->inet); break; #endif default: break; } ops->network_bind = ops->inet.network_bind; ops->inet.network_bind = ipnet_sock_udp_bind; ops->network_init = ops->inet.sock.init; ops->network_connect = ops->inet.sock.connect; ops->inet.sock.init = ipnet_sock_udp_init; ops->inet.sock.connect = ipnet_sock_udp_connect; ops->inet.sock.type = IP_SOCK_DGRAM; ops->inet.sock.proto = protos[p]; ops->inet.sock.allow_async_send = IP_TRUE; ops->inet.sock.usr_recv = ipnet_usr_sock_recvmsg; ops->inet.sock.send = ipnet_sock_udp_send; ops->inet.sock.hdr_space += IPNET_UDP_HDR_SIZE; ret = ipnet_sock_register_ops(&ops->inet.sock); if (ret < 0) return ret; } return 0; }
/* *=========================================================================== * ipcom_start_shell *=========================================================================== * Description: Starts a shell process and sets up a TCP connection. The * TCP connection is used to convey stdin and stdout data. The * stdio proxy process and the underlaying shell process is * terminated by closing the socket. If the shell terminates * (e.g. if the user gives the command 'exit') the stdio proxy * will close the TCP connection and terminate. * Parameters: * Returns: * */ IP_PUBLIC Ip_err ipcom_start_shell(Ip_fd *stdio_sock, Ip_fd client_fd) { Ip_fd mother = IP_INVALID_SOCKET; Ip_fd shell_fd = IP_INVALID_SOCKET; Ip_socklen_t addr_len; Ipcom_ipc ipc; Ipcom_shell_info *sinfo; char procname[40]; Ip_err retval; Ipcom_proc_attr attr; Ip_bool ipc_opened = IP_FALSE; Ip_pid_t ppid, shell_pid; Ip_u16 mother_port; static Ip_u32 seqno = 0; struct Ip_addrinfo hints; struct Ip_addrinfo *res = IP_NULL; union Ip_sockaddr_union sa; *stdio_sock = IP_INVALID_SOCKET; sinfo = ipcom_ipc_malloc(sizeof(Ipcom_shell_info)); if (sinfo == IP_NULL) { IPCOM_LOG0(ERR, "ipcom_start_shell :: ipcom_ipc_malloc() failed"); goto exit; } addr_len = sizeof(sinfo->sa_prompt); if (ipcom_getsockname(client_fd, (struct Ip_sockaddr *)&sinfo->sa_prompt, &addr_len) == IP_SOCKERR) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_getsockname(client_fd) failed, errno = %d", ipcom_errno); goto exit; } /* Get a tcp socket and let the stack pick a port */ ipcom_memset(&hints, 0, sizeof(hints)); hints.ai_family = sinfo->sa_prompt.sa.sa_family; hints.ai_socktype = IP_SOCK_STREAM; if (ipcom_getaddrinfo(IP_NULL, "0", &hints, &res) != 0) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_getsockname(client_fd) failed, errno = %d", ipcom_errno); goto exit; } mother = ipcom_socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (mother == IP_INVALID_SOCKET) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_socket(IP_AF_INET) failed, errno = %d", ipcom_errno); goto exit; } if (ipcom_bind(mother, res->ai_addr, res->ai_addrlen) == IP_SOCKERR) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_bind(IP_AF_INET) failed, errno = %d", ipcom_errno); goto exit; } /* Find out which port was assigned. */ addr_len = sizeof(sa); if (ipcom_getsockname(mother, (struct Ip_sockaddr *)&sa, &addr_len) == IP_SOCKERR) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_getsockname(IP_AF_INET) failed, errno = %d", ipcom_errno); goto exit; } mother_port = ip_ntohs(sa.sin.sin_port); if (ipcom_listen(mother, 1) == IP_SOCKERR) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_listen() failed, errno = %d", ipcom_errno); goto exit; } /* Create and start the shell process. */ ipcom_proc_attr_init(&attr); #ifdef IP_PORT_VXWORKS attr.stacksize = IPCOM_PROC_STACK_LARGE; #else attr.priority = IPCOM_PRIORITY_DEFAULT; #endif /* IP_PORT_VXWORKS */ ppid = ipcom_getpid(); ipcom_sprintf(procname, "ipcom_shell_%lx_%lx", (Ip_u32)ppid, ++seqno); if (ipcom_proc_acreate(procname, (Ipcom_proc_func)ipcom_shell, &attr, &shell_pid)) { IPCOM_LOG0(ERR, "ipcom_start_shell :: ipcom_proc_acreate() failed"); goto exit; } /* Open IPC with ipcom_shell. */ retval = ipcom_ipc_open(&ipc, procname, -1); if (retval != IPCOM_SUCCESS) { IPCOM_LOG2(ERR, "ipcom_start_shell :: ipcom_ipc_open(%s) failed, ret = %d", procname, retval); goto exit; } ipc_opened = IP_TRUE; /* Send a message to ipcom_shell. */ sinfo->port = mother_port; sinfo->ppid = ppid; sinfo->seqno = seqno; retval = ipcom_ipc_send(&ipc, sinfo); if (retval != IPCOM_SUCCESS) { IPCOM_LOG1(ERR, "ipcom_start_shell :: ipcom_ipc_send() failed, ret = %d", retval); goto exit; } /* Wait for the shell process to connect */ shell_fd = ipcom_accept(mother, IP_NULL, IP_NULL); exit: if (mother != IP_INVALID_SOCKET) (void)ipcom_socketclose(mother); if (res != IP_NULL) ipcom_freeaddrinfo(res); if (ipc_opened) (void)ipcom_ipc_close(&ipc); else if (sinfo != IP_NULL) ipcom_ipc_free(sinfo); if (shell_fd == IP_INVALID_SOCKET) return IPCOM_ERR_FAILED; else { int enable = IP_TRUE; *stdio_sock = shell_fd; /* Disable Nagle (enable no delay) on this socket since it is an interactive connection */ (void)ipcom_setsockopt(shell_fd, IP_IPPROTO_TCP, IP_TCP_NODELAY, &enable, sizeof(enable)); return IPCOM_SUCCESS; } }
/* *=========================================================================== * ipnet_sock_tcp_register *=========================================================================== * Description: Registers the TCP protocol for IPv4 and/or IPv6. * Parameters: * Returns: 0 = success, <0 = error code. * */ IP_GLOBAL int ipnet_sock_tcp_register(void) { Ipnet_sock_tcp_ops *ops; int domains[] = { #ifdef IPCOM_USE_INET IP_AF_INET, #endif #ifdef IPCOM_USE_INET6 IP_AF_INET6, #endif }; int protos[] = { 0, IP_IPPROTO_TCP }; Ip_size_t p, d; int ret; for (d = 0; d < sizeof(domains) / sizeof(domains[0]); d++) for (p = 0; p < sizeof(protos) / sizeof(protos[0]); p++) { ops = ipcom_calloc(1, sizeof(*ops)); if (ops == IP_NULL) { IPCOM_LOG0(CRIT, "Could not register the TCP protocol, out of memory"); IP_PANIC(); return -IP_ERRNO_ENOMEM; } switch (domains[d]) { #ifdef IPCOM_USE_INET case IP_AF_INET: ipnet_sock_ip4_get_ops(&ops->inet); break; #endif #ifdef IPCOM_USE_INET6 case IP_AF_INET6: ipnet_sock_ip6_get_ops(&ops->inet); break; #endif default: break; } ops->network_bind = ops->inet.network_bind; ops->inet.network_bind = ipnet_sock_tcp_bind; ops->network_init = ops->inet.sock.init; ops->inet.sock.init = ipnet_sock_tcp_init; ops->network_destroy = ops->inet.sock.destroy; ops->inet.sock.destroy = ipnet_sock_tcp_destroy; ops->network_connect = ops->inet.sock.connect; ops->inet.sock.connect = ipnet_sock_tcp_connect; ops->inet.sock.type = IP_SOCK_STREAM; ops->inet.sock.proto = protos[p]; ops->inet.sock.allow_async_send = IP_TRUE; ops->inet.sock.accept = iptcp_accept; ops->inet.sock.close = iptcp_close; ops->inet.sock.listen = iptcp_listen; ops->inet.sock.usr_recv = ipnet_usr_sock_tcp_recv; ops->inet.sock.pkts_from_iov = ipnet_usr_sock_tcp_pkts_from_iov; ops->inet.sock.send = iptcp_send; ops->inet.sock.shutdown = iptcp_shutdown; ops->inet.sock.getopt = iptcp_getsockopt; ops->inet.sock.setopt = iptcp_setsockopt; ops->inet.sock.ioctl = iptcp_ioctl; ops->inet.sock.hdr_space += IPTCP_TCP_HDR_SIZE; ops->inet.sock.extra_sock_space += sizeof(Iptcp_tcb); ret = ipnet_sock_register_ops(&ops->inet.sock); if (ret < 0) return ret; } return 0; }
/* *=========================================================================== * ipnet_nat_proxy_sip_payload_parse *=========================================================================== * Description: Parse SIP payload. * 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: IP_TRUE = Packet modified. * IP_FALSE = Packet untouched. */ IP_STATIC Ip_bool ipnet_nat_proxy_sip_payload_parse(Ip_u8 *appdata, int *applen, int growspace, Ipnet_nat_proxy_param *param, Ip_u8 **newdata) { char *psipmsg = (char *)appdata; char *pcallid = IP_NULL; char *pendstr, *pstartstr, *psearch; Ip_bool retcode = IP_FALSE; int pos, sdpdatalen, searchlen, msgtype = 0; char tmpholder[50]; char laddrstr[20]; char gaddrstr[20]; char *pend = (char *)sipbuf + *applen - 1; char *sdplen_start, *sdplen_end, *sdp_end; int newlen, diff; if (param->incoming == IP_TRUE) { /* Incoming message*/ goto parseFalseExit; } if (param->inbound == IP_FALSE) { /* Outbound session */ if ((psipmsg = ipnet_nat_proxy_sip_outboundmsgtypecheck(psipmsg, &msgtype, *applen)) == IP_NULL) return IP_FALSE; /* not the message we're looking for */ } else { /* Inbound session */ if ((psipmsg = ipnet_nat_proxy_sip_inboundmsgtypecheck(psipmsg, &msgtype, *applen)) == IP_NULL) return IP_FALSE; /* not the message we're looking for */ } /* find the call-id field */ if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_CALLID_STR, &pos, *applen - (psipmsg - (char *)appdata)) == IP_FALSE) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: no callid field"); return IP_FALSE; } /* get callid string */ pcallid = ipnet_nat_proxy_sip_callidstr(psipmsg + pos + SIP_TAG_TO_DATAPOS(SIP_CALLID_STR)); if (pcallid == IP_NULL) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: failed to parse callid string"); return IP_FALSE; } if (msgtype == SIP_MSG_TYPE_INVITE) { if (param->inbound == IP_FALSE) { /* Update the mapping timeout */ IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds", IPNET_NAT_SIP_ENTRY_INVITE_TIMEOUT); ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_INVITE_TIMEOUT, param->mapping); } else { /* ALG will not detect the ACK for inbound calls so use the INVITE response to set established timeout */ IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds", IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT); ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT, param->mapping); } } else if (msgtype == SIP_MSG_TYPE_ACK) { /* Update the mapping timeout */ IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds", IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT); ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT, param->mapping); } /* Copy the message to scratch buffer and set pointer */ if (*applen > (int)sizeof(sipbuf)) { IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: message to long"); goto parseFalseExit; } ipcom_memcpy(sipbuf, appdata, *applen); psipmsg = (char *)sipbuf + (psipmsg - (char *)appdata); /* first the via field * For response message, the Via field will not contain the private address. * The localAddrProcess() will check if the address is private. */ laddrstr[0] = gaddrstr[0] = 0; if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_VIA_STR, &pos, (pend - psipmsg) + 1) == IP_TRUE) { /* advance to IP/Port string */ psipmsg += (pos + ipcom_strlen(SIP_VIA_STR) + SIP_VIA_FIELD_IPADDR_DIS); IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse via field"); psipmsg = ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_ADDRESS_PORT_STRING, param, &pend); if (psipmsg == IP_NULL) goto parseFalseExit; } /* find the contact field */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTACT_STR, &pos, (pend - psipmsg) + 1) == IP_TRUE) { /* advance to IP/Port string */ psipmsg += (pos + ipcom_strlen(SIP_CONTACT_STR) + SIP_CTAC_FIELD_IPADDR_DIS); IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse contact field"); psipmsg = ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_ADDRESS_PORT_STRING, param, &pend); if (psipmsg == IP_NULL) goto parseFalseExit; } /* exit if there isn't any private info in SIP message header */ if (laddrstr[0] == 0 || gaddrstr[0] == 0) goto parseFalseExit; /* When program reaches here, it indicates at least one place in the * packet should be modified. Use parseFalseExit only if it is an error */ /* find the Content-Type field */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTYPE_STR, &pos, (pend - psipmsg) + 1) == IP_FALSE) goto parseTrueExit; /* advance to start of data field */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_CONTYPE_STR)); SIP_SKIP_SPACES(psipmsg); /*check the application/sdp type, if not, exit */ if (!SIP_IS_STRING_SAME(psipmsg, SIP_APPSDP_STR)) goto parseTrueExit; /* find the content length field */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTLEN_STR, &pos, (pend - psipmsg) + 1) == IP_FALSE) goto parseTrueExit; IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse Content-Length field"); /* reach to the content length field, advance to length data */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_CONTLEN_STR)); SIP_SKIP_SPACES(psipmsg); sdpdatalen = ipcom_strtol(psipmsg, &pendstr, 10); IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: data length = %d", sdpdatalen); if (sdpdatalen == 0) goto parseTrueExit; /* store start and end of sdp datalength string as well as end of message */ sdplen_start = psipmsg; sdplen_end = pendstr; sdp_end = pend; /* advance to the start of SDP data */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, IP_NULL, &pos, (pend - psipmsg) + 1) == IP_FALSE) { IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: Can't find header end mark"); goto parseTrueExit; } /* start of the SIP data field */ psipmsg += pos; searchlen = sdpdatalen; /* search the local IP address, and replace it with global address */ pstartstr = psipmsg; while (IP_TRUE) { psearch = ipnet_nat_proxy_sip_faststrsearch(laddrstr, ipcom_strlen(laddrstr), pstartstr, searchlen, IP_FALSE); if (psearch != IP_NULL) { IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: Local IP address in SDP: %s", laddrstr); if (ipnet_nat_proxy_sip_modmsg(gaddrstr, ipcom_strlen(gaddrstr), psearch, ipcom_strlen(laddrstr), &pend) < 0) { goto parseFalseExit; } searchlen = searchlen - (psearch + ipcom_strlen(gaddrstr) - pstartstr); pstartstr = psearch + ipcom_strlen(gaddrstr); } else break; } IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: the last search length %d", searchlen); /* search for the audio port */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_AUDIO_STR, &pos, sdpdatalen) == IP_TRUE) { /* advance to the port field */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_AUDIO_STR)); SIP_SKIP_SPACES(psipmsg); ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_PORT_STRING, param, &pend); } /* search for the audio control port */ if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_RTCP_STR, &pos, sdpdatalen) == IP_TRUE) { /* advance to the port field */ psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_RTCP_STR)); SIP_SKIP_SPACES(psipmsg); ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_PORT_STRING, param, &pend); } /* adjust the length node */ sdpdatalen += pend - sdp_end; ipcom_sprintf(tmpholder, "%d", sdpdatalen); if (ipnet_nat_proxy_sip_modmsg(tmpholder, ipcom_strlen(tmpholder), sdplen_start, sdplen_end - sdplen_start, &pend) < 0) { goto parseFalseExit; } parseTrueExit: /* Update application data with the modified buffer */ newlen = pend - (char *)sipbuf + 1; 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_sip_payload_parse() :: ipcom_malloc(%d) failed", *applen + diff); goto parseFalseExit; } ipcom_memcpy(*newdata, sipbuf, newlen); } else { /* Let the current buffer grow */ ipcom_memcpy(appdata, sipbuf, newlen); } *applen = newlen; IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_msg() :: the delta length = %d ", diff); retcode = IP_TRUE; parseFalseExit: if (msgtype == SIP_MSG_TYPE_BYE) ipnet_nat_proxy_sip_endmsgprocess(pcallid, param); if (pcallid) ipcom_free(pcallid); return retcode; }
/* *=========================================================================== * ipnet_if_mib_handler_ifTable *=========================================================================== * Description: MIB handler for variables in ifTable * Parameters: See file 'ipsnmp.h' * Returns: IPSNMP_ERROR_XXX * */ IP_STATIC Ip_s32 ipnet_if_mib_handler_ifTable(Ip_s32 cmd, char *id, Ipsnmp_varbind *vb, Ip_s32 magic, struct Ipsnmp_node_object *nodeobj) { Ip_s32 lid, ret = -1; Ipnet_netif *best_netif; Ip_s32 ifAdminStatus = 0; char *iid; char *buf = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID); char *best = ipcom_malloc(IPSNMP_CONFIG_MAX_OBJECT_ID); struct Ip_ifreq ifreq; Ip_fd fd; if (buf == IP_NULL || best == IP_NULL) { ret = IPSNMP_ERROR_GENERROR; goto exit; } lid = ipsnmp_util_last_subid(nodeobj->id); ip_assert(lid >= 1 && lid <= 20); ip_assert(lid != 12 && lid != 18); best_netif = ipnet_if_mib_table_search_ifTable(id, buf, best, cmd, &ret); if (best_netif == IP_NULL) goto exit; if (cmd == IPSNMP_MIB_COMMAND_GET || cmd == IPSNMP_MIB_COMMAND_NEXT) { iid = ipsnmp_create_iid_direct(nodeobj->id, best); if (iid == IP_NULL) { ret = IPSNMP_ERROR_GENERROR; goto exit; } switch(lid) { case 1: /* ifIndex */ ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.ifindex); break; case 2: /* ifDescr */ ret = ipsnmp_util_put_octetstring(magic, iid, (Ip_u8 *)best_netif->ipcom.name, ipcom_strlen(best_netif->ipcom.name)); break; case 3: /* ifType */ ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.type); break; case 4: /* ifMtu */ ret = ipsnmp_util_put_integer(magic, iid, best_netif->ipcom.mtu); break; case 5: /* ifSpeed */ if (best_netif->ipcom.type == IP_IFT_PPP) ret = ipsnmp_util_put_gauge32(magic, iid, IPCOM_DRV_PPP_BAUDRATE); else ret = ipsnmp_util_put_gauge32(magic, iid, 100000000); break; case 6: /* ifPhysAddr */ ret = ipsnmp_util_put_octetstring(magic, iid, best_netif->ipcom.link_addr, best_netif->ipcom.link_addr_size); break; case 7: /* ifAdminStatus */ if (IP_BIT_ISSET(best_netif->ipcom.flags, IP_IFF_UP)) ret = ipsnmp_util_put_integer(magic, iid, 1); else ret = ipsnmp_util_put_integer(magic, iid, 2); break; case 8: /* ifOperStatus */ if (IP_BIT_ISSET(best_netif->ipcom.flags, IP_IFF_UP)) ret = ipsnmp_util_put_integer(magic, iid, 1); else ret = ipsnmp_util_put_integer(magic, iid, 2); break; case 9: /* ifLastChange */ ret = ipsnmp_util_put_timeticks(magic, iid, best_netif->ipcom.mib2.ifLastChange); break; case 10: /* ifInOctets */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInOctets); break; case 11: /* ifInUcastPkts */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInUcastPkts); break; case 13: /* ifInDiscards */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInDiscards); break; case 14: /* ifInErrors */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInErrors); break; case 15: /* ifInUnknownProtos */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifInUnknownProtos); break; case 16: /* ifOutOctets */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutOctets); break; case 17: /* ifOutUcastPkts */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutUcastPkts); break; case 19: /* ifOutDiscards */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutDiscards); break; case 20: /* ifOutErrors */ ret = ipsnmp_util_put_counter32(magic, iid, best_netif->ipcom.mib2.ifOutErrors); break; default: IP_PANIC(); ret = IPSNMP_ERROR_GENERROR; break; } ipcom_free(iid); } if (cmd == IPSNMP_MIB_COMMAND_TEST || cmd == IPSNMP_MIB_COMMAND_SET) { switch(lid) { case 7: /* ifAdminStatus */ ret = ipsnmp_util_get_integer(vb, &ifAdminStatus); if (ret == IPSNMP_ERROR_NOERROR) { if (ifAdminStatus != 1 && ifAdminStatus != 2) { ret = IPSNMP_ERROR_WRONGVALUE; } } if (ret == IPSNMP_ERROR_NOERROR && cmd == IPSNMP_MIB_COMMAND_SET) { fd = ipnet_do_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP, IP_FALSE); if(fd != IP_INVALID_SOCKET) { /* Change interface status */ ipcom_memset(&ifreq, 0, sizeof(struct Ip_ifreq)); ipcom_strcpy(ifreq.ifr_name, best_netif->ipcom.name); if (ipnet_sys_socketioctl(fd, IP_SIOCGIFFLAGS, &ifreq) < 0) { IPCOM_LOG1(ERR, "Failed to get interface flags: %s", ipcom_strerror(ipcom_errno)); ret = IPSNMP_ERROR_GENERROR; } if (ifAdminStatus == 1) IP_BIT_SET(ifreq.ip_ifr_flags, IP_IFF_UP); else IP_BIT_CLR(ifreq.ip_ifr_flags, IP_IFF_UP); if (ipnet_sys_socketioctl(fd, IP_SIOCSIFFLAGS, &ifreq) < 0) { IPCOM_LOG1(ERR, "Failed to set interface flags: %s", ipcom_strerror(ipcom_errno)); ret = IPSNMP_ERROR_GENERROR; } ipnet_sys_socketclose(fd); } else { IPCOM_LOG0(ERR, "Failed to create socket for ioctl call"); ret = IPSNMP_ERROR_GENERROR; } } break; default: IP_PANIC(); ret = IPSNMP_ERROR_GENERROR; break; } } exit: if (buf != IP_NULL) ipcom_free(buf); if (best != IP_NULL) ipcom_free(best); return ret; }
/* *=========================================================================== * ipnet_config_add_inet6_addr *=========================================================================== * Description: * Parameters: * Returns: * */ IP_STATIC int ipnet_config_add_inet6_addr(Ip_fd fd, char *ifname, char *option) { char *opt; char *inet6_addr; char *prefix_len; char *argv[] = { "ifconfig", "-silent", IP_NULL, "inet6", "add", IP_NULL, IP_NULL, IP_NULL, IP_NULL, IP_NULL, IP_NULL }; int argc = 6; char inet6_addr_str[IP_INET6_ADDRSTRLEN]; char prefixlen_str[4]; argv[2] = ifname; for (;;) { /* Parse options */ opt = ipcom_strtok_r(option, " \t/", &option); if (opt == IP_NULL) { IPCOM_LOG0(ERR, "too few arguments"); return -IP_ERRNO_EINVAL; } if (ipcom_strcmp(opt, "tentative") == 0) argv[argc++] = opt; else break; } inet6_addr = opt; if (ipcom_strcmp(inet6_addr, "driver") == 0) { /* Get the IPv6 address to use from the driver */ struct Ip_ethreq ethreq; ipcom_strcpy(ethreq.ethr_name, ifname); if (ipcom_socketioctl(fd, IP_SIOCXETHGINET6, ðreq) < 0) { IPCOM_LOG1(ERR, "Failed to read the IPv6 address from the driver for %s", ifname); return ipcom_errno; } inet6_addr = inet6_addr_str; (void) ipcom_inet_ntop(IP_AF_INET6, ðreq.ethru.inet6.addr, inet6_addr_str, sizeof(inet6_addr_str)); ipcom_sprintf(prefixlen_str, "%u", ethreq.ethru.inet6.prefixlen); prefix_len = prefixlen_str; } else { prefix_len = ipcom_strtok_r(option, " \t/", &option); if (prefix_len == IP_NULL) { IPCOM_LOG0(ERR, "prefix len is missing or format is invalid"); return -IP_ERRNO_EINVAL; } } argv[5] = inet6_addr; argv[argc++] = "prefixlen"; argv[argc++] = prefix_len; return ipnet_config_cmd_ifconfig(argc, argv); }
/* *=========================================================================== * 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; }
/* *=========================================================================== * 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; }
/* *=========================================================================== * ipcom_waitif_gifaddr *=========================================================================== * Description: Get interface address. * Parameters: fd - socket descriptor * ifindex - Interface index. * domain - The address domain. * Returns: 0 = No address available, 1 = No address available, -1 = error. * */ IP_STATIC int ipcom_waitif_gifaddr(Ip_fd fd, int ifindex, int domain) { int ret = -1; switch (domain) { case IP_AF_INET: { struct Ip_ifreq ifreq; /* Get if name */ ipcom_memset(&ifreq, 0, sizeof(ifreq)); (void)ipcom_if_indextoname(ifindex, ifreq.ifr_name); /* Get main address */ if (ipcom_socketioctl(fd, IP_SIOCGIFADDR, &ifreq) < 0) { if (ipcom_errno != IP_ERRNO_EADDRNOTAVAIL && ipcom_errno != IP_ERRNO_ENXIO) { IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_socketioctl(SIOCGIFADDR) failed, errno = %d", ipcom_errno); } } else { struct Ip_in_addr network = ((struct Ip_sockaddr_in *)&ifreq.ip_ifr_addr)->sin_addr; if (network.s_addr != IP_INADDR_DEFAULT) { ret = 0; } } break; } #ifdef IPCOM_USE_INET6 case IP_AF_INET6: { int len = IPNET_WAITIF_MAXIF * sizeof(struct Ip_ifreq); char ifname[IP_IFNAMSIZ]; struct Ip_ifconf ifc; char *buf = IP_NULL; char *ptr; /* Get if name */ (void)ipcom_if_indextoname(ifindex, ifname); /* Get if data buffer */ if ((buf = ipcom_malloc(IPNET_WAITIF_MAXIF * sizeof(struct Ip_ifreq))) == IP_NULL) { IPCOM_LOG0(ERR, "ipcom_waitif :: Out of memory"); goto leave; } /* Enter buf in ifconf struct */ ifc.ifc_len = len; ifc.ip_ifc_buf = buf; if (ipcom_socketioctl(fd, IP_SIOCGIFCONF, &ifc) < 0) { IPCOM_LOG1(ERR, "ipcom_socketioctl(SIOCGIFCONF) failed, errno = %d\n", ipcom_errno); goto leave; } /* Loop for all interfaces */ for (ptr = buf; ptr < buf + ifc.ifc_len; ) { struct Ip_ifreq *ifr = (struct Ip_ifreq *)ptr; char *cptr; /* Calculate pointer to next if */ len = IP_MAX(sizeof(struct Ip_sockaddr_in), ifr->ip_ifr_addr.sa_len); ptr += sizeof(ifr->ifr_name) + len; if ((cptr = ipcom_strchr(ifr->ifr_name, ':')) != IP_NULL) { *cptr = '\0'; } /* Only for v6 addresses */ if (ipcom_strcmp(ifr->ifr_name, ifname) == 0 && ifr->ip_ifr_addr.sa_family == IP_AF_INET6) { struct Ip_sockaddr_in6 *in6 = (struct Ip_sockaddr_in6 *)&ifr->ip_ifr_addr; if (!IP_IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) { ret = 0; break; } } } leave: if (buf != IP_NULL) { ipcom_free(buf); } break; } #endif /* IPCOM_USE_INET6 */ } return ret; }
/* *=========================================================================== * ipnet_nat_proxy_dns_request *=========================================================================== * Description: Parse and modify DNS request. * 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_request(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, remainder; 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_request() :: 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) != 0 || /* Not a request */ (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_request() :: invalid header"); return 0; } /* Copy the header */ if (newbuflen - newlen < (int)sizeof(*dns_hdr)) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_request() :: 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; /* Copy the rest of the message */ remainder = *applen - offset; if (remainder) { if (newbuflen - newlen < remainder) { IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_request() :: no space left in modified buffer"); return 0; } ipcom_memcpy(&dnsbuf[newlen], appdata+offset, remainder); newlen += remainder; offset += remainder; } /* 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_request() :: 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_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; }
/* *=========================================================================== * ipcom_shell_print_prompt *=========================================================================== * Description: Print shell prompt. * Parameters: * Returns: 0 = success, <0 = error code. * */ IP_STATIC int ipcom_shell_print_prompt(char *prompt_template, char *prompt_addr, int *promptlen, Ip_pid_t ppid, Ip_u32 seqno) { int baselen; int ret = 0; int buflen = 0; char *buf; #if IPCOM_USE_FILE != IPCOM_FILE_NONE char *cwd; char *base; char cwdbuf[128]; #endif buf = ipcom_malloc(IPCOM_STDIO_BUFSIZE); if (buf == IP_NULL) return -1; for (; *prompt_template != '\0'; ++prompt_template) { ip_assert(buflen < (int)IPCOM_STDIO_BUFSIZE - 1); if (*prompt_template != '\\') { /* 'Normal' character */ buf[buflen++] = *prompt_template; } else { /* New special character*/ switch (*++prompt_template) { case 'w': /* Print current working directory */ case 'W': #if IPCOM_USE_FILE != IPCOM_FILE_NONE /* Print basename of the current workning directory */ cwd = ipcom_getcwd(cwdbuf, sizeof(cwdbuf)); if (cwd == IP_NULL) { IPCOM_LOG0(DEBUG, "ipcom_shell_print_prompt :: ipcom_getcwd() failed"); break; } if (*prompt_template == 'w') base = cwd; else { base = ipcom_strrchr(cwd, '/'); if (base != IP_NULL && base != cwd) base++; else { base = ipcom_strrchr(cwd, '\\'); if (base == IP_NULL) base = cwd; else base++; } } baselen = ipcom_strlen(base); ipcom_memcpy(buf + buflen, base, baselen); buflen += baselen; #endif break; case 'p': /* Print the shell process name */ { char procname[40]; ipcom_sprintf(procname, "ipcom_shell_%lx_%lx", (Ip_u32)ppid, seqno); baselen = ipcom_strlen(procname); ipcom_memcpy(buf + buflen, procname, baselen); buflen += baselen; } break; case 'P': /* Print the shell process pid */ { char pid[14]; ipcom_sprintf(pid, "0x%lx", ipcom_getpid()); baselen = ipcom_strlen(pid); ipcom_memcpy(buf + buflen, pid, baselen); buflen += baselen; } break; case 'i': /* Print the IP address */ if (*prompt_addr) { baselen = ipcom_strlen(prompt_addr); ipcom_memcpy(buf + buflen, prompt_addr, baselen); buflen += baselen; } break; #if IPCOM_USE_ENV != IPCOM_ENV_NONE case 'V': { char vrbuf[16]; baselen = ipcom_sprintf(vrbuf, "%d", ipcom_proc_vr_get()); ipcom_memcpy(buf + buflen, vrbuf, baselen); buflen += baselen; } break; #endif default: /* Unknown code. */ IPCOM_LOG1(DEBUG, "ipcom_shell_print_prompt :: unknown code: %c", *prompt_template); buf[buflen++] = '\\'; buf[buflen++] = '\\'; buf[buflen++] = *prompt_template; break; } } } if (buflen > 0) { buf[buflen] = '\0'; if (promptlen != IP_NULL) *promptlen = ipcom_strlen(buf); ipcom_printf(buf); } ipcom_free(buf); if (ret < 0) IPCOM_LOG0(WARNING, "ipcom_shell_print_prompt :: ipcom_printf() failed"); return ret; }