/*
 *===========================================================================
 *                    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, &ethreq) < 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, &ethreq) < 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, &ethreq.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(&ethreq.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);
}
Esempio n. 2
0
/*
 *===========================================================================
 *                    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;
}
Esempio n. 5
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;
}
Esempio n. 6
0
/*
 *===========================================================================
 *                    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;
}
Esempio n. 7
0
/*
 *===========================================================================
 *                    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;
}
Esempio n. 8
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;
}
Esempio n. 9
0
/*
 *===========================================================================
 *                    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 */
}
Esempio n. 13
0
/*
 *===========================================================================
 *                    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;
}
Esempio n. 14
0
/*
 *===========================================================================
 *                    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 */
}
Esempio n. 15
0
/*
 *===========================================================================
 *                    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;
    }
}
Esempio n. 17
0
/*
 *===========================================================================
 *                    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;
}
Esempio n. 18
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;
}
Esempio n. 19
0
/*
 *===========================================================================
 *                      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, &ethreq) < 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, &ethreq.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;
}
Esempio n. 25
0
/*
 *===========================================================================
 *                    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;
}