/*
 *===========================================================================
 *                    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);
}
/****************************************************************************
 *
 * example_do_command - Execute a DHCPS command
 *
 * This routine execute a DHCPS command containing the parameters we're
 * interested in adding to the configuration.
 * 
 * .IP <format> 
 * The format string
 *
 * .IP <...>
 * The arguments for the format string
 * 
 * RETURNS:
 * N/A
 *
 * NOMANUAL
 */
IP_STATIC void
example_do_command(const char *format, ...)
{
    va_list     vargs;
    char        *cmd;
    int         argc;
    char        **argv = IP_NULL;

    if ((cmd = ipcom_malloc(256)) != IP_NULL)
    {
        va_start(vargs, format);
        ipcom_vsnprintf(cmd, 256, format, vargs);        
        va_end(vargs);       

        
        IPCOM_LOG1(INFO,"DHCP Executing '%s'", cmd);
        if(ipcom_parse_argstr(cmd, (int*)&argc, &argv) != IPCOM_SUCCESS)
        {
            IPCOM_LOG1(ERR,"failed to parse command '%s'", cmd);
            goto out;
        }

        if(ipdhcps_cmd_dhcps(argc, argv) != IPCOM_SUCCESS)
        {
            IPCOM_LOG1(ERR,"failed to execute command '%s'", cmd);
            goto out;
        }

out:
        if (argv != IP_NULL)
            ipcom_free(argv);
        if (cmd)
            ipcom_free(cmd);
    }
}
Esempio n. 3
0
/*
 *===========================================================================
 *                    ipnet_nat_proxy_sip_endmsgprocess
 *===========================================================================
 * Description: Cleanup the resource created for a given SIP session
 * Parameters:
 * Returns:     nothing.
 */
IP_STATIC void
ipnet_nat_proxy_sip_endmsgprocess(char *pcallid, Ipnet_nat_proxy_param *param)
{
    if (pcallid != IP_NULL)
        IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_endmsgprocess() :: callid=%s", pcallid);
    if (param != IP_NULL)
    {
        /* Update the mapping timeout */
        IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_endmsgprocess() :: setting mapping timeout to %d seconds",
                   IPNET_NAT_SIP_ENTRY_BYE_TIMEOUT);
        ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_BYE_TIMEOUT, param->mapping);
    }
}
/*
 *===========================================================================
 *                      ipnet_pkt_queue_mbc_configure
 *===========================================================================
 * Description: Configures a queue with new parameters.
 * Parameters:  q - A packet queue.
 *              m - The queue parameters.
 * Returns:     0  = success
 *              <0 = error code
 */
IP_STATIC int
ipnet_pkt_queue_mbc_configure(Ipnet_pkt_queue_mbc *q, struct Ipnet_ifqueue_mbc *m)
{
    Ip_u32 band;

    if (q->number_of_bands)
    {
        IPCOM_LOG0(ERR, "MBC configure: Can only be configured once");
        return -IP_ERRNO_EINVAL;
    }

    if (m->mbc_bands < 2 || m->mbc_bands > IPNET_IFQ_CONTAINER_MAX_COUNT)
    {
        IPCOM_LOG1(ERR,
                   "MBC configure: Number of priority bands must be between 2 and %d",
                   IPNET_IFQ_CONTAINER_MAX_COUNT);
        return -IP_ERRNO_EINVAL;
    }

    if (m->mbc_bands <= m->mbc_default_band)
    {
        IPCOM_LOG1(ERR, "MBC configure: invalid default band, must be [0..%d]",
                   m->mbc_bands - 1);
        return -IP_ERRNO_EINVAL;
    }

    q->bands = ipcom_calloc(m->mbc_bands, sizeof(Ipnet_pkt_queue *));
    if (q->bands == IP_NULL)
    {
        IPCOM_LOG0(CRIT, "MBC configure: out of memory");
        return -IP_ERRNO_ENOMEM;
    }

    q->number_of_bands = m->mbc_bands;
    q->default_band    = m->mbc_default_band;

    for (band = 0; band < q->number_of_bands; band++)
    {
        int                    ret;

        ret = ipnet_pkt_queue_mbc_insert_default_queue(q, band);
        if (ret < 0)
        {
            IPCOM_LOG1(ERR, "MBC configure: Failed to create default queue: %s",
                       ipcom_strerror(-ret));
            return ret;
        }
    }

    return 0;
}
/*
 *===========================================================================
 *                  ipnet_pkt_queue_mbc_insert
 *===========================================================================
 * Description: Inserts an queue to a container queue.
 * Parameters:  c - The parent queue for 'q', must be container capable
 *              q - The queue to insert.
 * Returns:     0 = success, <0 = error code (-IP_ERRNO_xxx)
 *
 */
IP_STATIC int
ipnet_pkt_queue_mbc_insert(Ipnet_pkt_queue_mbc *c, Ipnet_pkt_queue *q)
{
    Ip_u32           band;

    for (band = 0; band < c->number_of_bands; band++)
    {
        if (c->bands[band] == IP_NULL)
        {
            /* Is adding the initial queues */
            c->bands[band] = q;
            return 0;
        }

        if (q->id == c->bands[band]->id)
        {
            /* Replace this queue */
            ipnet_pkt_queue_delete(c->bands[band]);
            c->bands[band] = q;
            return 0;
        }
    }
    IPCOM_LOG1(ERR, "MBC: No band has queue id %d", q->id);
    return -IP_ERRNO_ESRCH;
}
Esempio n. 6
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. 7
0
/*
 *===========================================================================
 *                    ipnet_nat_proxy_sip_keyfind
 *===========================================================================
 * Description: Find a string in a structured message.
 *              This routine searches a string in a structured message.
 *              It assumes the searched string always starts at the beginning
 *              of each line of data terminated by \r\n characters. A message
 *              should be terminated by \r\n preceded by the line terminator
 *              \r\n.
 * Parameters:  pdata     - pointer to message.
 *              pstr      - key to look for.
 *              ppos      - found string position relative to pdata.
 *              searchlen - searchlen.
 * Returns:     IP_TRUE  = found key.
 *              IP_FALSE = key not found.
 */
IP_STATIC Ip_bool
ipnet_nat_proxy_sip_keyfind(char *pdata,
                            char *pstr,
                            int  *ppos,
                            int  searchlen)
{
    char *pstart = pdata;
    int        i = 0;

    if (!searchlen)
        searchlen = 1000;  /* max default search length */

    while (IP_TRUE)
    {
        if (pstr)
        {
            /* skip all space */
            while (*pdata == ' ')
                pdata++;

            if (ipcom_memcmp(pdata, pstr, ipcom_strlen(pstr)) == 0)
                break;
        }

        /* advance to next line */
        for (i = 0; i < (searchlen - 1); i++)
        {
            if (pdata[i] == '\r')
                if (pdata[i+1] == '\n')
                    break;
        }

        if (i >= (searchlen - 1))
        {
            IPCOM_LOG1(ERR, "ipnet_nat_proxy_sip_keyfind() :: single message exceeds max len: %d", searchlen);
            *ppos = searchlen;  /* reaches the end */
            return IP_FALSE;
        }

        pdata += i + 2;
        searchlen -= (i + 2);

        if ((pdata[0] == '\r' && pdata[1] == '\n') || (searchlen <= 0))
        {
            /* reach the end mark \r\n\r\n */
            if (searchlen)
                pdata += 2;

            *ppos = pdata - pstart;

            return (pstr ? IP_FALSE : IP_TRUE);
        }
    }

    *ppos = pdata - pstart;
    return IP_TRUE;
}
/*
 *===========================================================================
 *                    ipnet_config_add_gateway
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_config_add_gateway(Ip_fd fd, char *ifname, char *option)
{
    char gw_str[IP_INET_ADDRSTRLEN];
    char *gw;

    gw = ipcom_strtok_r(option, " \t", &option);
    if (gw == IP_NULL)
    {
        IPCOM_LOG1(ERR,
                   "Wrong gateway format specified for interface %s, must be 'gateway <driver|gw_address>",
                   ifname);
        IP_PANIC();
        return -IP_ERRNO_EINVAL;
    }

    if (ipcom_strcmp(gw, "driver") == 0)
    {
        /* Get the IPv4 gateway 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 gateway address "
                       "from the driver for %s", ifname);
            return ipcom_errno;
        }
        if (ethreq.ethru.inet.gateway.s_addr == 0xffffffff)
            return 0; /* using dhcp, ignore gateway */
        if (ethreq.ethru.inet.gateway.s_addr == 0)
        {
            IPCOM_LOG1(NOTICE, "No IPv4 gateway address set in driver for %s", ifname);
            return 0;
        }

        (void) ipcom_inet_ntop(IP_AF_INET, &ethreq.ethru.inet.gateway,
                               gw_str, sizeof(gw_str));
        gw = gw_str;
    }

    return ipnet_config_add_route(IP_AF_INET, "0.0.0.0", 0, gw);
}
/*
 *===========================================================================
 *                    ipnet_config_run_boot_cmd
 *===========================================================================
 * Description: Configures one route entry.
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_config_run_boot_cmd(const char *conf)
{
    char *option_org;
    char *option;
    char *argv[20];
    char *arg;
    int   argc = 0;
    int   ret = -IP_ERRNO_EINVAL;

    option_org = option = ipcom_strdup(conf);
    if (option == IP_NULL)
        return -IP_ERRNO_ENOMEM;

    while (IP_NULL != (arg = ipcom_strtok_r(option, " \t", &option)))
    {
        if (argc == 1)
            argv[argc++] = "-silent";
        argv[argc++] = arg;

        if (argc >= (int) (sizeof(argv) / sizeof(*argv)))
        {
            IPCOM_LOG1(ERR, "Too many arguments in command %s", conf);
            IP_PANIC();
        }
    }
    argv[argc] = IP_NULL;

    if (argc > 2)
    {
        if (ipcom_strcmp(argv[0], "route") == 0)
            ret = ipnet_config_cmd_route(argc, argv);
        else if (ipcom_strcmp(argv[0], "ifconfig") == 0)
            ret = ipnet_config_cmd_ifconfig(argc, argv);
        else if (ipcom_strcmp(argv[0], "qc") == 0)
            ret = ipnet_config_cmd_qc(argc, argv);
#if defined(IPNET_USE_NAT) && !defined(IP_PORT_LKM) && !defined(IP_PORT_VXWORKS)
        else if (ipcom_strcmp(argv[0], "nat") == 0)
            ret = ipnet_cmd_nat(argc, argv);
#endif
    }

    ipcom_free(option_org);
    return ret;
}
/*****************************************************************************
 * 
 * example_parse_option - Parse a ISC option string
 *
 * .IP <tok>
 * The tokenizer buffer
 *
 * .IP <context>
 * The context the option resides in
 *
 * RETURNS:
 * 0 on success.
 *
 * NOMANUAL
 */
IP_STATIC Ip_s32
example_parse_option(example_token_buffer_t *tok, const char *context)
{
    /* Retrieve the option name */
    char *option = example_get_token(tok, IP_FALSE);
    if (option == IP_NULL)
    {
        IPCOM_LOG1(ERR, 
                   "DHCPS(%d): no option name specified",
                   tok->curline);
        return -1;

    }

    if (ipcom_strcasecmp(option, "domain-name-servers") == 0)
    {
        /* DNS servers option; retrieve the list of servers and pass it
         * to our dhcps command */
        char *value = example_concatenate_tokens(tok);

        if (value == IP_NULL)
        {
            IPCOM_LOG1(ERR, 
                       "DHCPS(%d): No servers specified or lacking ';' in domain-name-servers option",
                       tok->curline);
            return -1;
        }

        example_do_command("dhcps option add %s 5 %s", context, value);
        ipcom_free(value);
    }
    else if (ipcom_strcasecmp(option, "domain-name") == 0)
    {
        /* A domain name */
        char *value = example_get_token(tok, IP_FALSE);
        if (!example_check_token(tok, ";", IP_FALSE))
        {
            IPCOM_LOG1(ERR, 
                       "DHCPS(%d): No domain name specified or lacking ';' in domain-name option",
                       tok->curline);
            return -1;
        }
        
        example_do_command("dhcps option add %s 15 %s", context, value);
    }
    else if (ipcom_strcasecmp(option, "routers") == 0)
    {
        /* One or many routers */
        char *value = example_concatenate_tokens(tok);
        if (value == IP_NULL)
        {
            IPCOM_LOG1(ERR, 
                       "DHCPS(%d): No servers specified or lacking ';' in routers option",
                       tok->curline);
            return -1;
        }

        example_do_command("dhcps option add %s 3 %s", context, value);
        ipcom_free(value);
    }
    else
    {
        /* Unknown or unhandled option */
        IPCOM_LOG2(WARNING, 
                   "DHCPS(%d): Unknown option %s",
                   tok->curline, 
                   option);
        return -1;
    }

    return 0;
}
/*
 *===========================================================================
 *                    ipnet_nat_proxy_dns_request
 *===========================================================================
 * Description: Parse and modify DNS request.
 * Parameters:  appdata   - pointer to application data.
 *              applen    - pointer to length of application data.
 *              growspace - space available to extend application data.
 *              param     - pointer to proxy parameters.
 *              newdata   - pointer to pointer to new application data.
 * Returns:     1 = Packet modified.
 *              0 = Packet untouched.
 */
IP_STATIC int
ipnet_nat_proxy_dns_request(Ip_u8 *appdata,
                            int   *applen,
                            int    growspace,
                            Ipnet_nat_proxy_param *param,
                            Ip_u8 **newdata)
{
    Ipnet_nat_dns_hdr *dns_hdr;
    Ip_u16 flags;
    int offset, diff, qlen, remainder;
    int newbuflen = sizeof(dnsbuf);
    int newlen    = 0;

    /* Check that at least a header is included */
    if (*applen < (int)sizeof(*dns_hdr))
    {
        IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_request() :: message too short for dns header");
        return 0;
    }
    dns_hdr = (Ipnet_nat_dns_hdr *)appdata;
    flags = IP_GET_NTOHS(&dns_hdr->flags);
    if((flags & IPNET_NAT_DNS_QR_FLAG)     != 0 ||  /* Not a request */
       (flags & IPNET_NAT_DNS_OPCODE_FLAG) != 0 ||  /* Not a standard query */
       (flags & IPNET_NAT_DNS_TC_FLAG)     != 0)    /* Truncated */
    {
        IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_request() :: invalid header");
        return 0;
    }

    /* Copy the header */
    if (newbuflen - newlen < (int)sizeof(*dns_hdr))
    {
        IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_request() :: no space left in modified buffer");
        return 0;
    }
    ipcom_memcpy(&dnsbuf[newlen], dns_hdr, sizeof(*dns_hdr));
    newlen += sizeof(*dns_hdr);

    /* Get the questions */
    offset = sizeof(*dns_hdr);
    qlen   = ipnet_nat_proxy_dns_parse_questions(appdata, *applen, offset, &newlen, dns_hdr, param);
    if (qlen < 0)
        return 0;
    offset += qlen;

    /* Copy the rest of the message */
    remainder = *applen - offset;
    if (remainder)
    {
        if (newbuflen - newlen < remainder)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_request() :: no space left in modified buffer");
            return 0;
        }
        ipcom_memcpy(&dnsbuf[newlen], appdata+offset, remainder);
        newlen += remainder;
        offset += remainder;
    }

    /* Update application data with the modified buffer */
    diff = newlen - *applen;
    if (diff > growspace)
    {
        /* Must allocate a new buffer */
        *newdata = ipcom_malloc(*applen + diff);
        if (*newdata == IP_NULL)
        {
            IPCOM_LOG1(ERR, "ipnet_nat_proxy_dns_request() :: ipcom_malloc(%d) failed",
                            *applen + diff);
            return -1;
        }
        ipcom_memcpy(*newdata, dnsbuf, newlen);
    }
    else
    {
        /* Let the current buffer grow */
        ipcom_memcpy(appdata, dnsbuf, newlen);
    }
    *applen = newlen;
    return 1;
}
/*
 *===========================================================================
 *                    ipnet_nat_proxy_dns_parse_answers
 *===========================================================================
 * Description: Parses and modifies DNS answers in a DNS packet.
 * Parameters:  buf     - pointer to buffer with the DNS questions.
 *              buflen  - length of buffer with DNS questions.
 *              offset  - offset in the buffer where the DNS questions begin.
 *              newlen  - pointer to the length of the message if modified.
 *              dns_hdr - pointer to the DNS protocol header.
 *              param   - pointer to NAT proxy parameters.
 * Returns:     The number of bytes parsed or -1 if failed.
 */
IP_STATIC Ip_s32
ipnet_nat_proxy_dns_parse_answers(Ip_u8 *buf,
                              int buflen,
                              int offset,
                              int *newlen,
                              Ipnet_nat_dns_hdr *dns_hdr,
                              Ipnet_nat_proxy_param *param)
{
    int i, count, origoffset, numa;
    Ip_u16 type, cla, rlen;
    int newbuflen = sizeof(dnsbuf);
    Ipnet_nat_dns_transaction *trans;

    numa = IP_GET_NTOHS(&dns_hdr->no_answ);
    origoffset = offset;
    for (i=0; i<numa; i++)
    {
        /* Get the name */
        count = ipnet_nat_proxy_dns_decode_name(buf, buflen, offset, dnsname, sizeof(dnsname));
        if (count < 0)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: could not decode dns name");
            return -1;
        }

        /* Copy the name */
        if (newbuflen - *newlen < count)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
            return -1;
        }
        ipcom_memcpy(&dnsbuf[*newlen], buf+offset, count);
        *newlen += count;
        offset  += count;

        /* Check space for type, class, ttl and record length */
        if (buflen - offset < 10)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: message too short to parse answer");
            return -1;
        }

        /* Get the type */
        type = (Ip_u16)(IP_GET_NTOHS(buf+offset));
        switch(type)
        {
            case IPNET_NAT_DNS_QTYPE_A:
                type = IPNET_NAT_DNS_QTYPE_AAAA;
                break;
            case IPNET_NAT_DNS_QTYPE_PTR:
                trans = ipnet_nat_proxy_dns_find_transaction(IPNET_NAT_DNS_QTYPE_PTR, dns_hdr, param);
                if (trans != IP_NULL)
                {
                    IPCOM_LOG4(DEBUG, "ipnet_nat_proxy_dns_parse_answers() :: found transaction:"
                                      "id=%d port=%d addr=0x%08x type=%d",
                                       trans->id, trans->srcport, trans->dstaddr, trans->type);
                    *newlen -= count;   /* Move index back to before the name */
                    count = ipnet_nat_proxy_dns_encode_name(dnsbuf, newbuflen, *newlen, trans->ptrname);
                    if (count < 0)
                    {
                        ipnet_nat_proxy_dns_remove_transaction(trans);
                        IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_questions() :: could not encode dns name");
                        return -1;
                    }
                    *newlen += count;
                    if (i+1 == numa)
                    {
                        /* Remove transaction for last answer */
                        ipnet_nat_proxy_dns_remove_transaction(trans);
                    }
                }
                break;
            default:
                break;
        }
        /* Copy the type */
        if (newbuflen - *newlen < 2)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
            return -1;
        }
        IP_SET_HTONS(&dnsbuf[*newlen], type);
        *newlen += 2;
        offset  += 2;

        /* Get the class */
        cla = (Ip_u16)(IP_GET_NTOHS(buf+offset));
        if (cla != IPNET_NAT_DNS_QCLASS_INET)
        {
            IPCOM_LOG1(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: unhandled class: %d", cla);
            return -1;
        }
        /* Copy the class */
        if (newbuflen - *newlen < 2)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
            return -1;
        }
        IP_SET_HTONS(&dnsbuf[*newlen], cla);
        *newlen += 2;
        offset  += 2;

        /* Copy the ttl */
        if (newbuflen - *newlen < 4)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
            return -1;
        }
        ipcom_memcpy(&dnsbuf[*newlen], buf+offset, 4);
        *newlen += 4;
        offset  += 4;

        /* Get the record length */
        rlen = (Ip_u16)(IP_GET_NTOHS(buf+offset));
        if (buflen - offset < rlen)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: message too short to parse answer");
            return -1;
        }

        /* Copy the record length */
        if (newbuflen - *newlen < 2)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
            return -1;
        }
        if (type == IPNET_NAT_DNS_QTYPE_AAAA && rlen == 4)
        {
            /* Modify record length and make space for the AAAA record */
            IP_SET_HTONS(&dnsbuf[*newlen], 16);
            *newlen += 2;
            /* Insert AAAA record data  */
            if (newbuflen - *newlen < 12)
            {
                IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
                return -1;
            }
            ipcom_memcpy(&dnsbuf[*newlen], param->prefix, 12);
            *newlen += 12;
        }
        else
        {
            IP_SET_HTONS(&dnsbuf[*newlen], rlen);
            *newlen += 2;
        }
        offset += 2;

        /* Copy the record */
        if (newbuflen - *newlen < rlen)
        {
            IPCOM_LOG0(WARNING, "ipnet_nat_proxy_dns_parse_answers() :: no space left in modified buffer");
            return -1;
        }
        ipcom_memcpy(&dnsbuf[*newlen], buf+offset, rlen);
        *newlen += rlen;
        offset  += rlen;
    }

    return offset - origoffset;
}
/*
 *===========================================================================
 *                    ipnet_nat_proxy_dns_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;
}
/*
 *===========================================================================
 *                    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;
    }
}
/*
 *===========================================================================
 *                    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;
}
Esempio n. 16
0
/*
 *===========================================================================
 *                    ipnet_nat_proxy_sip_payload_parse
 *===========================================================================
 * Description: Parse SIP payload.
 * Parameters:  appdata   - pointer to application data.
 *              applen    - pointer to length of application data.
 *              growspace - space available to extend application data.
 *              param     - pointer to proxy parameters.
 *              newdata   - pointer to pointer to new application data.
 * Returns:     IP_TRUE  = Packet modified.
 *              IP_FALSE = Packet untouched.
 */
IP_STATIC Ip_bool
ipnet_nat_proxy_sip_payload_parse(Ip_u8 *appdata,
                                  int   *applen,
                                  int    growspace,
                                  Ipnet_nat_proxy_param *param,
                                  Ip_u8 **newdata)

{
    char    *psipmsg = (char *)appdata;
    char    *pcallid = IP_NULL;
    char    *pendstr, *pstartstr, *psearch;
    Ip_bool  retcode = IP_FALSE;
    int      pos, sdpdatalen, searchlen, msgtype = 0;
    char     tmpholder[50];
    char     laddrstr[20];
    char     gaddrstr[20];
    char    *pend = (char *)sipbuf + *applen - 1;
    char    *sdplen_start, *sdplen_end, *sdp_end;
    int      newlen, diff;

    if (param->incoming == IP_TRUE)
    {
        /* Incoming message*/
        goto parseFalseExit;
    }

    if (param->inbound == IP_FALSE)
    {
        /* Outbound session */
        if ((psipmsg = ipnet_nat_proxy_sip_outboundmsgtypecheck(psipmsg, &msgtype, *applen)) == IP_NULL)
            return IP_FALSE;   /* not the message we're looking for */
    }
    else
    {
        /* Inbound session */
        if ((psipmsg = ipnet_nat_proxy_sip_inboundmsgtypecheck(psipmsg, &msgtype, *applen)) == IP_NULL)
            return IP_FALSE;   /* not the message we're looking for */
    }

    /* find the call-id field */
    if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_CALLID_STR, &pos, *applen - (psipmsg - (char *)appdata)) == IP_FALSE)
    {
        IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: no callid field");
        return IP_FALSE;
    }

    /* get callid string */
    pcallid = ipnet_nat_proxy_sip_callidstr(psipmsg + pos + SIP_TAG_TO_DATAPOS(SIP_CALLID_STR));
    if (pcallid == IP_NULL)
    {
        IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: failed to parse callid string");
        return IP_FALSE;
    }

    if (msgtype == SIP_MSG_TYPE_INVITE)
    {
        if (param->inbound == IP_FALSE)
        {
            /* Update the mapping timeout */
            IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds",
                       IPNET_NAT_SIP_ENTRY_INVITE_TIMEOUT);
            ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_INVITE_TIMEOUT, param->mapping);
        }
        else
        {
            /* ALG will not detect the ACK for inbound calls so use the INVITE response to set established timeout */
            IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds",
                       IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT);
            ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT, param->mapping);
        }
    }
    else if (msgtype == SIP_MSG_TYPE_ACK)
    {
        /* Update the mapping timeout */
        IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: setting mapping timeout to %d seconds",
                   IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT);
        ipnet_nat_proxy_set_mapping_timeout(IPNET_NAT_SIP_ENTRY_ESTABLISHED_TIMEOUT, param->mapping);
    }

    /* Copy the message to scratch buffer and set pointer */
    if (*applen > (int)sizeof(sipbuf))
    {
        IPCOM_LOG0(ERR, "ipnet_nat_proxy_sip_payload_parse() :: message to long");
        goto parseFalseExit;
    }
    ipcom_memcpy(sipbuf, appdata, *applen);
    psipmsg = (char *)sipbuf + (psipmsg - (char *)appdata);

    /* first the via field
     * For response message, the Via field will not contain the private address.
     * The localAddrProcess() will check if the address is private.
     */

    laddrstr[0] = gaddrstr[0] = 0;
    if (ipnet_nat_proxy_sip_keyfind(psipmsg, SIP_VIA_STR, &pos, (pend - psipmsg) + 1) == IP_TRUE)
	{
        /* advance to IP/Port string */

        psipmsg += (pos + ipcom_strlen(SIP_VIA_STR) + SIP_VIA_FIELD_IPADDR_DIS);

        IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse via field");

        psipmsg = ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid,
                                                       SIP_ADDRESS_PORT_STRING, param, &pend);

        if (psipmsg == IP_NULL)
            goto parseFalseExit;

    }

    /* find the contact field */

    if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTACT_STR, &pos, (pend - psipmsg) + 1) == IP_TRUE)
    {
        /* advance to IP/Port string */

        psipmsg += (pos + ipcom_strlen(SIP_CONTACT_STR) + SIP_CTAC_FIELD_IPADDR_DIS);

        IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse contact field");

        psipmsg = ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid,
                                                       SIP_ADDRESS_PORT_STRING, param, &pend);

        if (psipmsg == IP_NULL)
            goto parseFalseExit;
    }

    /* exit if there isn't any private info in SIP message header */

    if (laddrstr[0] == 0 || gaddrstr[0] == 0)
        goto parseFalseExit;

    /* When program reaches here, it indicates at least one place in the
     * packet should be modified. Use parseFalseExit only if it is an error
     */

    /* find the Content-Type field */

    if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTYPE_STR, &pos, (pend - psipmsg) + 1) == IP_FALSE)
        goto parseTrueExit;

    /* advance to start of data field */

    psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_CONTYPE_STR));

    SIP_SKIP_SPACES(psipmsg);

    /*check the application/sdp type, if not, exit */

    if (!SIP_IS_STRING_SAME(psipmsg, SIP_APPSDP_STR))
        goto parseTrueExit;

    /* find the content length field */

    if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_CONTLEN_STR, &pos, (pend - psipmsg) + 1) == IP_FALSE)
        goto parseTrueExit;

    IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: parse Content-Length field");

    /* reach to the content length field, advance to length data */

    psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_CONTLEN_STR));

    SIP_SKIP_SPACES(psipmsg);

    sdpdatalen = ipcom_strtol(psipmsg, &pendstr, 10);

    IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: data length = %d", sdpdatalen);

    if (sdpdatalen == 0)
        goto parseTrueExit;

    /* store start and end of sdp datalength string as well as end of message */
    sdplen_start = psipmsg;
    sdplen_end   = pendstr;
    sdp_end      = pend;

    /* advance to the start of SDP data */

    if (ipnet_nat_proxy_sip_keyfind (psipmsg, IP_NULL, &pos, (pend - psipmsg) + 1) == IP_FALSE)
    {
        IPCOM_LOG0(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: Can't find header end mark");
        goto parseTrueExit;
    }

    /* start of the SIP data field */

    psipmsg += pos;
    searchlen = sdpdatalen;

    /* search the local IP address, and replace it with global address */

    pstartstr = psipmsg;
    while (IP_TRUE)
    {
        psearch = ipnet_nat_proxy_sip_faststrsearch(laddrstr, ipcom_strlen(laddrstr),
                                                    pstartstr, searchlen, IP_FALSE);
        if (psearch != IP_NULL)
        {
            IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: Local IP address in SDP: %s", laddrstr);

            if (ipnet_nat_proxy_sip_modmsg(gaddrstr, ipcom_strlen(gaddrstr),
                                           psearch, ipcom_strlen(laddrstr), &pend) < 0)
            {
                goto parseFalseExit;
            }

            searchlen = searchlen - (psearch + ipcom_strlen(gaddrstr) - pstartstr);
            pstartstr = psearch + ipcom_strlen(gaddrstr);
        }
        else
            break;
    }

    IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_payload_parse() :: the last search length %d", searchlen);

    /* search for the audio port */

    if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_AUDIO_STR, &pos, sdpdatalen) == IP_TRUE)
    {
        /* advance to the port field */

        psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_AUDIO_STR));

        SIP_SKIP_SPACES(psipmsg);
        ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_PORT_STRING, param, &pend);
    }

    /* search for the audio control port */

    if (ipnet_nat_proxy_sip_keyfind (psipmsg, SIP_RTCP_STR, &pos, sdpdatalen) == IP_TRUE)
	{
        /* advance to the port field */

        psipmsg += (pos + SIP_TAG_TO_DATAPOS(SIP_RTCP_STR));

        SIP_SKIP_SPACES(psipmsg);
        ipnet_nat_proxy_sip_localaddrprocess(psipmsg, laddrstr, gaddrstr, pcallid, SIP_PORT_STRING, param, &pend);
    }

    /* adjust the length node */

    sdpdatalen += pend - sdp_end;
    ipcom_sprintf(tmpholder, "%d", sdpdatalen);
    if (ipnet_nat_proxy_sip_modmsg(tmpholder, ipcom_strlen(tmpholder),
                                   sdplen_start, sdplen_end - sdplen_start, &pend) < 0)
    {
        goto parseFalseExit;
    }

parseTrueExit:
    /* Update application data with the modified buffer */
    newlen = pend - (char *)sipbuf + 1;
    diff = newlen - *applen;
    if (diff > growspace)
    {
        /* Must allocate a new buffer */
        *newdata = ipcom_malloc(*applen + diff);
        if (*newdata == IP_NULL)
        {
            IPCOM_LOG1(ERR, "ipnet_nat_proxy_sip_payload_parse() :: ipcom_malloc(%d) failed",
                            *applen + diff);
            goto parseFalseExit;
        }
        ipcom_memcpy(*newdata, sipbuf, newlen);
    }
    else
    {
        /* Let the current buffer grow */
        ipcom_memcpy(appdata, sipbuf, newlen);
    }
    *applen = newlen;
    IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_msg() :: the delta length = %d ", diff);
    retcode = IP_TRUE;

parseFalseExit:
    if (msgtype == SIP_MSG_TYPE_BYE)
        ipnet_nat_proxy_sip_endmsgprocess(pcallid, param);
    if (pcallid)
        ipcom_free(pcallid);
    return retcode;
}
/*
 *===========================================================================
 *                    ipnet_config_add_route
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_STATIC int
ipnet_config_add_route(int domain, char *addr, int prefix_len, char *gateway)
{
    char *argv[] = {
        "route",
        "add",
        "-silent",
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
        IP_NULL,
    };
    int argc = 4;
    int max_prefix_len;
    union Ipnet_addr mask;
    union Ipnet_addr dst_addr;
    char dst_str[IP_INET6_ADDRSTRLEN];
    char prefix_len_str[4];
    int ret;

#ifdef IPCOM_USE_INET
    if (domain == IP_AF_INET)
    {
        max_prefix_len = 32;
        argv[3] = "-inet";
    }
    else
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
    if (domain == IP_AF_INET6)
    {
        max_prefix_len = 128;
        argv[3] = "-inet6";
    }
    else
#endif /* IPCOM_USE_INET6 */
    {
        /* Unsupported domain */
        IPCOM_LOG1(ERR, "unsupported domain: %d", domain);
        return -IP_ERRNO_EAFNOSUPPORT;
    }

    if (prefix_len == -1)
        /* Host route */
        prefix_len = max_prefix_len;

    if (addr == IP_NULL || gateway == IP_NULL || prefix_len < 0 || prefix_len > max_prefix_len)
        return -IP_ERRNO_EINVAL;

    if (ipcom_inet_pton(domain, addr, &dst_addr) != 1)
    {
        IPCOM_LOG2(ERR, "invalid %s address format: %s",
            (domain == IP_AF_INET) ? "inet" : "inet6", addr);
        return -IP_ERRNO_EINVAL;
    }

    /* Apply mask */
    ipcom_memset(&mask, 0, sizeof(mask));
    ipnet_route_create_mask(&mask, prefix_len);
    ipnet_route_apply_mask(&dst_addr, &mask, max_prefix_len);
    (void) ipcom_inet_ntop(domain, &dst_addr, dst_str, sizeof(dst_str));

    argv[argc++] = "-static";

    if (prefix_len == max_prefix_len)
        argv[argc++] = "-host";
    else
    {
        argv[argc++] = "-net";
        argv[argc++] = "-prefixlen";
        ipcom_sprintf(prefix_len_str, "%d", prefix_len);
        argv[argc++] = prefix_len_str;
    }

    argv[argc++] = dst_str;
    argv[argc++] = gateway;

    ret = ipnet_config_cmd_route(argc, argv);
    if (ret == IP_ERRNO_EEXIST)
        return 0;
    return ret;
}
/*
 *===========================================================================
 *                    ipnet_boot_config
 *===========================================================================
 * Description: Adds the initial configuration to the stack.
 * Parameters:
 * Returns:
 *
 */
IP_GLOBAL int
ipnet_boot_config()
{
    const char *key;
    const char *ifname = IP_NULL;
    int         begin_index;
    int         end_index;
    int         err = 0;
    Ip_fd       fd;

#ifdef IPCOM_USE_INET
    fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, 0);
#else
    fd = ipcom_socket(IP_AF_INET6, IP_SOCK_DGRAM, 0);
#endif
    if (fd == IP_SOCKERR)
    {
        IP_PANIC2();
        err = -ipcom_errno;
        goto leave;
    }

    /* Configure interfaces. */
    begin_index = 0;
    while (ipnet_conf_interfaces[begin_index] != IP_NULL)
    {
        end_index = begin_index;
        while (ipnet_conf_interfaces[end_index] != IP_NULL)
        {
            key = ipcom_strstr((const char *)ipnet_conf_interfaces[end_index], "ifname");
            if (key != IP_NULL)
            {
                ifname = key + 6;
                while(*ifname && (*ifname == ' ' || *ifname == '\t'))
                    ifname++;
            }
            end_index++;
        }
        ip_assert(ifname != IP_NULL);
        err = ipnet_config_interface(fd,
                                     (char *)ifname,
                                     (char **) &ipnet_conf_interfaces[begin_index],
                                     end_index - begin_index,
                                     1);
        if (err >= 0)
        {
            /* Run all pending ioctls since the addresses are not added until that is done
               which means that adding of gateway will fail since it cannot be reached */
            err = ipnet_config_interface(fd,
                                         (char *)ifname,
                                         (char **) &ipnet_conf_interfaces[begin_index],
                                         end_index - begin_index,
                                         2);
        }
#if defined (WRS_IPNET)
        if (err >= 0 && ipnet_qc_unif_config_hook != IP_NULL)
        {
	    err = ipnet_qc_unif_config_hook (ifname);
        }
#endif /* defined (WRS_IPNET) */
        if (err < 0)
        {
            IP_PANIC2();
            goto leave;
        }
        begin_index = end_index + 1;
    }

    /* Run boot configuration commands. */
    for (begin_index = 0; ipnet_conf_boot_cmd[begin_index] != IP_NULL; begin_index++)
    {
        err = ipnet_config_run_boot_cmd(ipnet_conf_boot_cmd[begin_index]);
        if (err < 0)
        {
            IPCOM_LOG1(ERR, "Configuration failed to run '%s'", ipnet_conf_boot_cmd[begin_index]);
            IP_PANIC2();
            goto leave;
        }
    }

 leave:
    if (fd != IP_INVALID_SOCKET)
        (void)ipcom_socketclose(fd);
    return err;
}
/*
 *===========================================================================
 *                    ipnet_config_interface
 *===========================================================================
 * Description: Configures one interface if it exists and is UP.
 * Parameters:  fd - A socket descriptor
 *              ifname - The name of the interface to configure
 *              conf - The configuration to apply to the interface
 *              conf_len - Number of valid entries in the "conf" array
 *              pass - First pass (1) will add all addresses
 *                     second pass (2) will add other things like gateways
 * Returns:     0 = success
 *             <0 = error code
 *
 */
IP_STATIC int
ipnet_config_interface(Ip_fd fd, char *ifname, char *conf[], int conf_len, int pass)
{
    char *option;
    char *option_org;
    char *token;
    int   i;
    int   err;

    ip_assert(pass == 1 || pass == 2);

    if (ipcom_if_nametoindex(ifname) == 0)
    {
        /* Interface does not exist */
        IPCOM_LOG1(INFO, "%s not attached - skipping", ifname);
        return 0;
    }

    if (0 > (err = ipnet_config_bring_up_if(ifname)))
    {
        IPCOM_LOG1(INFO, "Failed to bring UP %s", ifname);
        return 0;
    }

    for (i = 0; i < conf_len; i++)
    {
        option_org = option = ipcom_strdup(conf[i]);
        if (option == IP_NULL)
            return -IP_ERRNO_ENOMEM;

        token = ipcom_strtok_r(option, " \t/", &option);

        if (token == IP_NULL || ipcom_strcmp(token, "ifname") == 0)
        {
            /* Ignore */
            err = 0;
        }
#ifdef IPCOM_USE_INET
        else if (ipcom_strcmp(token, "inet") == 0)
        {
            if (pass == 1)
                err = ipnet_config_add_inet_addr(fd, ifname, option);
        }
        else if (ipcom_strcmp(token, "gateway") == 0)
        {
            if (pass == 2)
                err = ipnet_config_add_gateway(fd, ifname, option);
        }
#else
        else if (ipcom_strcmp(token, "inet") == 0
                 || ipcom_strcmp(token, "gateway") == 0)
            IP_NOOP;
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
        else if (ipcom_strcmp(token, "inet6") == 0)
        {
            if (pass == 1)
                err = ipnet_config_add_inet6_addr(fd, ifname, option);
        }
        else if (ipcom_strcmp(token, "gateway6") == 0)
        {
            if (pass == 2)
                err = ipnet_config_add_gateway6(ifname, option);
        }
#else
        else if (ipcom_strcmp(token, "inet6") == 0
                 || ipcom_strcmp(token, "gateway6") == 0)
            IP_NOOP;
#endif /* IPCOM_USE_INET6 */
        else if (ipcom_strcmp(token, "devname") != 0)
            /* Invalid configuration */
            err = -IP_ERRNO_EINVAL;

        ipcom_free(option_org);
        if (err != 0)
        {
            if (err < 0)
                err = -err;
            IPCOM_LOG4(ERR, "failed on '%s' when configuring %s: %s (%d)",
                conf[i], ifname, ipcom_strerror(err), err);
            IP_PANIC();
            break;
        }
    }

    return err;
}
/*
 *===========================================================================
 *                    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);
}
/*
 *===========================================================================
 *                    ipcom_getifaddrs
 *===========================================================================
 * Description:
 * Parameters:
 * Returns:
 *
 */
IP_PUBLIC int
ipcom_getifaddrs(struct Ip_ifaddrs **ifa)
{
    int                     name[6];
    Ip_u8                   *if_data;
    Ip_size_t               if_data_len;
    Ip_size_t               if_data_offset;
    struct Ipnet_if_msghdr  *ifm;
    struct Ip_ifaddrs       **tail  = ifa;
    struct Ip_sockaddr_dl   *dl;
    struct Ipnet_rt_msghdr  *rtm;
    Ip_fd                   fd = IP_INVALID_SOCKET;
    char                    ifname[IP_IFNAMSIZ];
    Ip_size_t               if_name_len;

    if(ifa == IP_NULL)
        return -1;
    *ifa = IP_NULL;


    name[0] = IP_CTL_NET;
    name[1] = IP_AF_ROUTE;
    name[2] = 0;    /* Always 0 */
    name[3] = 0;
    name[4] = IP_NET_RT_IFLIST;
    name[5] = 0;

redo_alloc:
    if (ipcom_sysctl(name, 6, IP_NULL, &if_data_len, IP_NULL, 0) < 0)
    {
        IPCOM_LOG1(ERR, "ipcom_getifaddrs() :: ipcom_sysctl(%d) failed!"IP_LF, ipcom_errno);
        return -1;
    }

    if_data = ipcom_malloc(if_data_len);
    if (if_data == IP_NULL)
    {
        IPCOM_LOG1(ERR, "ipcom_getifaddrs() :: ipcom_malloc(%d) failed!"IP_LF, if_data_len);
        return -1;
    }

    if (ipcom_sysctl(name, 6, if_data, &if_data_len, IP_NULL, 0) < 0)
    {
        if (ipcom_errno == IP_ERRNO_ENOMEM)
        {
            ipcom_free(if_data);
            goto redo_alloc;
        }

        IPCOM_LOG1(ERR, "ipcom_getifaddrs() :: ipcom_sysctl(%d) failed!"IP_LF, ipcom_errno);
        goto cleanup;
    }

#if defined(IPCOM_USE_INET)
    fd = ipcom_socket(IP_AF_INET, IP_SOCK_DGRAM, IP_IPPROTO_UDP);
#elif defined(IPCOM_USE_INET6)
    fd = ipcom_socket(IP_AF_INET6, IP_SOCK_DGRAM, IP_IPPROTO_UDP);
#endif
    if (fd == IP_INVALID_SOCKET)
        goto cleanup;

    if_data_offset = 0;
    while (if_data_len > if_data_offset + sizeof(struct Ipnet_if_msghdr))
    {
        ifm = (struct Ipnet_if_msghdr *) &if_data[if_data_offset];
        if_data_offset += ifm->ifm_msglen;
        rtm = (struct Ipnet_rt_msghdr *)(void *)ifm;
        switch (rtm->rtm_type) {
			case IPNET_RTM_IFINFO:
				if (ifm->ifm_addrs & IPNET_RTA_IFP) {
					dl = (struct Ip_sockaddr_dl *)(void *)(ifm + 1);
					ipcom_memset(ifname,0,IP_IFNAMSIZ);
					ipcom_memcpy(ifname, dl->sdl_data,(Ip_size_t)dl->sdl_nlen);
					break; /* Got the name! */
				}
			default:
				continue; /* No name, continue */
        }        
        
#ifdef IPCOM_USE_INET
        if_data_offset += ipcom_create_ifaddrs_inet(fd,
                                                    ifname,
                                                    &if_data[if_data_offset],
                                                    if_data_len - if_data_offset,
                                                    ifm,
                                                    &tail);
#endif /* IPCOM_USE_INET */
#ifdef IPCOM_USE_INET6
        if_data_offset += ipcom_create_ifaddrs_inet6(fd,
                                                     ifname,
                                                     &if_data[if_data_offset],
                                                     if_data_len - if_data_offset,
                                                     ifm,
                                                     &tail);
#endif /* IPCOM_USE_INET6 */


    }

cleanup:
    if (fd != IP_INVALID_SOCKET)
        ipcom_socketclose(fd);
    ipcom_free(if_data);
    return 0;
}
/*****************************************************************************
 * 
 * example_parse_subnet - Parse an ISC subnet directive
 *
 * .IP <tok>
 * The tokenizer buffer.
 *
 * RETURNS:
 * 0 on success
 *
 * NOMANUAL
 */
IP_STATIC Ip_s32
example_parse_subnet(example_token_buffer_t *tok)
{
    /* address NETMASK netmask { */
    char            *address, *netmask;
    char            *token;

    /* We need to retrieve the address, the NETMASK keyword and the
     * netmask value */
    address = example_get_token(tok, IP_FALSE);
    if (!example_check_token(tok, "netmask", IP_FALSE))
        return -1;
    netmask = example_get_token(tok, IP_FALSE);

    /**/
    if (address == IP_NULL || netmask == IP_NULL)
        return -1;

    /* The subnet block starts with a left bracer */
    if (!example_check_token(tok, "{", IP_TRUE))
        return -1;

    /* Add the subnet command */
    example_do_command("dhcps subnet add %s %s", address, netmask);

    /* Go through the subnet */
    while ((token = example_get_token(tok, IP_TRUE)) != IP_NULL)
    {
        int retval;

        /* End of subnet is a right bracer, exit successfully if found */
        if (ipcom_strcasecmp(token, "}") == 0)
            return 0;
        else if (ipcom_strcasecmp(token, "option") == 0)
        {
            /* Parse a subnet specific option */
            if ((retval = example_parse_option(tok, address)) != 0)
                return retval;            
        }        
        else if (ipcom_strcasecmp(token, "range") == 0)
        {
            /* Parse a pool range */
            char *start, *end;
            start   = example_get_token(tok, IP_FALSE);
            end     = example_get_token(tok, IP_FALSE);
            if (!example_check_token(tok, ";", IP_FALSE))
            {
                IPCOM_LOG1(ERR, 
                           "DHCPS(%d): Missing range start, end or ';' in range directive",
                           tok->curline);
                return -1;
            }

            example_do_command("dhcps pool add %s %s %s", address, start, end);
        }
        else if (ipcom_strcasecmp(token, "default-lease-time") == 0)
        {
            char *lease;
            lease   = example_get_token(tok, IP_FALSE);
            if (!example_check_token(tok, ";", IP_FALSE))
            {
                IPCOM_LOG1(ERR, 
                           "DHCPS(%d): lease time specified or ';' missing in default-lease-time directive",
                           tok->curline);
                return -1;
            }

            example_do_command("dhcps config set %s default-lease-time %s", address, lease);
        }
        else if (ipcom_strcasecmp(token, "max-lease-time") == 0)
        {
            char *lease;
            lease   = example_get_token(tok, IP_FALSE);
            if (!example_check_token(tok, ";", IP_FALSE))
            {
                IPCOM_LOG1(ERR, 
                           "DHCPS(%d): lease time specified or ';' missing in max-lease-time directive",
                           tok->curline);
                return -1;
            }

            example_do_command("dhcps config set %s max-lease-time %s", address, lease);
        }
    }
}
/*****************************************************************************
 *
 * example_parse_base -  Parse top-level ISC configuration items
 * 
 * .IP <tok>
 * The tokenizer buffer
 *
 * RETURNS:
 * 0 on success
 *
 * NOMANUAL
 */
IP_STATIC Ip_s32
example_parse_base(example_token_buffer_t *tok)
{
    for (;;)
    {
        char *token = example_get_token(tok, IP_TRUE);
        char *value;
        int ret;

        /* EOF; We've read the entire file - exit */
        if (token == IP_NULL)
            return 0;

        /* Check the token and see if we know it */
        if (ipcom_strcasecmp(token, "subnet") == 0)
        {
            ret = example_parse_subnet(tok);
        }
        else if (ipcom_strcasecmp(token, "option") == 0)
        {
            ret = example_parse_option(tok, "default");
        }
        else if (ipcom_strcasecmp(token, "default-lease-time") == 0)
        {
            value   = example_get_token(tok, IP_FALSE);
            if (!example_check_token(tok, ";", IP_FALSE))
            {
                IPCOM_LOG1(ERR, 
                           "DHCPS(%d): lease time specified or ';' missing in default-lease-time directive",
                           tok->curline);
                return -1;
            }

            example_do_command("dhcps config set default default-lease-time %s", value);
        }
        else if (ipcom_strcasecmp(token, "max-lease-time") == 0)
        {
            value   = example_get_token(tok, IP_FALSE);
            if (!example_check_token(tok, ";", IP_FALSE))
            {
                IPCOM_LOG1(ERR, 
                           "DHCPS(%d): lease time specified or ';' missing in max-lease-time directive",
                           tok->curline);
                return -1;
            }

            example_do_command("dhcps config set default max-lease-time %s", value);
        }
        else if (ipcom_strcasecmp(token, "authoritative") == 0 ||
                 ipcom_strcasecmp(token, "ddns-update-style") == 0 ||
                 ipcom_strcasecmp(token, "log-facility") == 0)
        {
            /* Unsupported ISC directives
             * Consume this line
             */
            IPCOM_LOG2(WARNING, 
                       "DHCPS(%d): Unhandled directive %s specified",
                       tok->curline,
                       token);
            example_get_line(tok);
        }
    }    
}
/*****************************************************************************
 *
 * example_cfgfile - Read an ISC DHCP configuration file
 * 
 * .IP <cfgfile>
 * The configuration file
 *
 * RETURNS:
 * 0 on success, -1 or errorcode otherwise.
 *
 * NOMANUAL
 */
IP_GLOBAL Ip_s32
example_isc_config(const char *cfgfile)
{
    int retval = -1;
    char *buf = IP_NULL;
    IP_FILE *fd  = IP_NULL;
    struct Ip_stat st;
    example_token_buffer_t tbuf;

    /* Failed to read */
    if (ipcom_stat(cfgfile, &st) != 0)
    {
        IPCOM_LOG1(ERR, 
                   "DHCPS: Failed to stat configuration file %s",
                   cfgfile);
        goto leave;
    }

    /* Failed to open */
    if((fd = ipcom_fopen(cfgfile,"r")) == 0)
    {
        IPCOM_LOG1(ERR, 
                   "DHCPS: Failed to open configuration file %s",
                   cfgfile);
        goto leave;
    }

    /* Allocate buffer */
    if ((buf = ipcom_malloc(st.st_size + 1)) == IP_NULL)
    {
        IPCOM_LOG1(ERR, 
                   "DHCPS: Failed to allocate memory for configuration file %s",
                   cfgfile);
        goto leave;
    }

    /* Read entire file */
    if((ipcom_fread(buf, 1, st.st_size, fd)) != st.st_size)
    {
        IPCOM_LOG1(ERR, 
                   "DHCPS: Failed to read configuration file %s",
                   cfgfile);
        goto leave;
    }

    /* Zero terminate; */
    buf[st.st_size] = '\0';

    /* Do parse the configuration file */
    ipcom_memset(&tbuf, 0, sizeof(tbuf));
    tbuf.lines = buf;
    example_get_line(&tbuf);

    /* Parse the file */
    retval = example_parse_base(&tbuf);

leave:
    if (fd)
        ipcom_fclose(fd);
    if(buf != IP_NULL)
        ipcom_free(buf);
    return retval;
}
Esempio n. 25
0
/*
 *===========================================================================
 *                    ipnet_nat_proxy_sip_localaddrprocess
 *===========================================================================
 * Description: Process the private transport address
 * Parameters:  pmsgstr    - pointer to message
 *              pipaddrstr - pointer to buffer for the local address string
 *              pgaddrstr  - pointer to buffer for the gloab address string
 *              pcallid    - pointer to the call id string
 *              type       - type of search
 *              ppend      - pointer to pointer to last byte of message
 * Returns:     The next character position after the parsed string or
 *	            IP_NULL if parse fails
 */
IP_STATIC char *
ipnet_nat_proxy_sip_localaddrprocess(char *pmsgstr,
                                     char *pipaddrstr,
                                     char *pgaddrstr,
                                     char *pcallid,
                                     int  type,
                                     Ipnet_nat_proxy_param *param,
                                     char **ppend)
{
    int localport, newport;
    int len, diff;
    Ip_u32 ipaddr;
    char *pstart;
    char tmpholder[30];
    Ipnet_nat_proxy_tuple proxy_tuple;

    (void)pcallid;
    SIP_SKIP_SPACES(pmsgstr);

    pstart = pmsgstr;
    pmsgstr = ipnet_nat_proxy_sip_addrportstrparse(pmsgstr, &ipaddr, &localport, type);

    if (pmsgstr == IP_NULL)
        return IP_NULL;

    if (!localport)
        localport = SIP_DEFAULT_PORT;

    if (type == SIP_ADDRESS_PORT_STRING)
    {
        ipaddr = ip_htonl(ipaddr);
        (void)ipcom_inet_ntop(IP_AF_INET, &ipaddr, pipaddrstr, 16);
        ipaddr = ip_ntohl(ipaddr);
    }
    else  /* PORT string only */
    {
        ipaddr = ipcom_inet_addr(pipaddrstr);
        ipaddr = ip_ntohl(ipaddr);
    }

    /* make sure it is the private address, otherwise no translation */

    if (ipaddr != param->tuple.private_addr)
        return pmsgstr;

    /* create a bind entry for this transport address if it hasn't been created yet */
    if (param->tuple.private_port != localport)
    {
        ipcom_memset(&proxy_tuple, 0, sizeof(proxy_tuple));
        proxy_tuple.protocol     = IP_IPPROTO_UDP;
        proxy_tuple.private_addr = ipaddr;
        proxy_tuple.private_port = localport;
        newport = ipnet_nat_proxy_add_mapping(&proxy_tuple,
                                              IPNET_NAT_SIP_ENTRY_MEDIA_TIMEOUT,
                                              param->mapping,
                                              IP_FALSE,         /* Use port translation */
                                              IP_TRUE,          /* Inbound session */
                                              IP_NULL,
                                              IP_NULL);

        if (newport < 0)
        {
            IPCOM_LOG2(ERR, "ipnet_nat_proxy_sip_localaddrprocess() :: Failed to add mapping for address = 0x%08x, port = %d",
                       ipaddr, localport);
        }
        else
        {
            IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_sip_localaddrprocess() :: Added mapping for address = 0x%08x, port = %d",
                       ipaddr, localport);
        }
    }
    else
    {
        newport = param->nat_port;
        IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_sip_localaddrprocess() :: Mapping already existed for address = 0x%08x, port = %d",
                   ipaddr, localport);
    }

    /* compose the new modified string */

    len = 0;
    if (type == SIP_ADDRESS_PORT_STRING)
    {
        ipaddr = ip_htonl(param->nat_addr);
        (void)ipcom_inet_ntop(IP_AF_INET, &ipaddr, tmpholder, 16);
        ipcom_strcpy(pgaddrstr, tmpholder);
        len = ipcom_strlen(tmpholder);
        tmpholder[len++]= ':';
    }
    ipcom_sprintf(tmpholder + len, "%d", newport);

    IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_sip_localaddrprocess() new str: %s", tmpholder);


    if (ipnet_nat_proxy_sip_modmsg(tmpholder, ipcom_strlen(tmpholder),
                                   pstart, pmsgstr - pstart, ppend) < 0)
    {
        return IP_NULL;
    }

    diff = ipcom_strlen(tmpholder) - (pmsgstr - pstart);
    return pmsgstr + diff;
}
Esempio n. 26
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;
}
/*
 *===========================================================================
 *                    ipcom_waitif
 *===========================================================================
 * Description: Wait for interface to get an IP address assigned.
 * Parameters:  ifindex - Index of the interface to wait for.
 *                        0 = any interface except loopback.
 *              domain - The address domain.
 * Returns:     0 = success, -1 = error, and sets errno.
 *
 */
IP_PUBLIC int
ipcom_waitif(int ifindex, int domain)
{
    struct Ipnet_rs_msghdr rtmsg;
    struct Ip_timeval stop;
    struct Ip_timeval tv;
    Ip_fd fd = IP_INVALID_SOCKET;
    int ret = -1;

    /* Check domain */
    if (domain != IP_AF_INET
#ifdef IPCOM_USE_INET6
        && domain != IP_AF_INET6
#endif /* IPCOM_USE_INET6 */
       )
    {
        IPCOM_LOG1(ERR, "ipcom_waitif :: invalid domain: %d", domain);
        ipcom_errno_set(IP_ERRNO_EINVAL);
        goto leave;
    }

    /* Get routing socket */
    fd = ipcom_socket(IP_AF_ROUTE, IP_SOCK_RAW, 0);
    if (fd == IP_INVALID_SOCKET)
    {
        IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_socket(ROUTE, RAW) failed, errno = %d", ipcom_errno);
        goto leave;
    }

    /* Get stop time */
    ipcom_microtime(&tv);
    stop.tv_sec = tv.tv_sec + IPNET_WAITIF_TIMEOUT;

    /* Loop and wait for address */
    for (;;)
    {
        Ip_ssize_t length;

        /* Check if address available */
        if (ifindex == 0)
        {
            int i;

            /* Any if will do */
            for (i = 2; i < IPNET_WAITIF_MAXIF; i++)
            {
                if (ipcom_waitif_gifaddr(fd, i, domain) == 0)
                {
                    ret = 0;
                    goto leave;
                }
            }
        }
        else if (ipcom_waitif_gifaddr(fd, ifindex, domain) == 0)
        {
            ret = 0;
            goto leave;
        }

again:
        /* Get timeout time */
        ipcom_microtime(&tv);
        tv.tv_sec = stop.tv_sec - tv.tv_sec;
        tv.tv_usec = 0;
        if (tv.tv_sec <= 0)
        {
            ipcom_errno_set(IP_ERRNO_ETIMEDOUT);
            goto leave;
        }

        /* Set receive timeout */
        if (ipcom_setsockopt(fd, IP_SOL_SOCKET, IP_SO_RCVTIMEO, &tv, sizeof(tv)) < 0)
        {
            IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_setsockopt(RCVTIMEO) failed, errno = %d", ipcom_errno);
            goto leave;
        }

        /* Read routing message headers only (truncated read). */
        length = ipcom_recv(fd, &rtmsg, sizeof(rtmsg), 0);
        if (length == IP_SOCKERR)
        {
            if (ipcom_errno != IP_ERRNO_ETIMEDOUT && ipcom_errno != IP_ERRNO_EWOULDBLOCK)
            {
                IPCOM_LOG1(ERR, "ipcom_waitif :: ipcom_recv() failed, errno = %d", ipcom_errno);
            }

            goto leave;
        }

        /* Only bother about newaddr */
        if (rtmsg.type != IPNET_RTM_NEWADDR)
        {
            goto again;
        }
    }

leave:
    if (fd != IP_INVALID_SOCKET)
    {
        ipcom_socketclose(fd);
    }

    return ret;
}
Esempio n. 28
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. 29
0
/*
 *===========================================================================
 *                    ipnet_nat_proxy_h245_msg
 *===========================================================================
 * Description: Track H.245 packets.
 * This function handles the H.245 call control 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.245 port. The H.245 port was
 * negotiated during the H.225 call signaling session and registered to NAT.
 * The H.245 call control protocol is used in H.323 to negotiate call parameters
 * between two end-points.  For example, it negotiates the UDP connections for
 * the open logical channels for RTP and RTCP streams between the two endpoints.
 * In addition, it also negotiates the TCP connection for the T1.120 session.
 *
 * NOTE 1:
 * The H.245 message is ASN.1 encoded. However, due to resource and schedule
 * constraint, rather than employing an ASN.1 decoder, this function uses a simple
 * work-around alternative which appears to work just as well.  This work-around
 * strategy looks for the ip+port address in the H.245 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.245 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.
 *
 * For an outbound packet, L may be sending its transport addresses to G to let
 * G make TCP/UDP connections to it.  Similarly, for an inbound packet, G may be
 * sending its transport addresses to L to let L make TCP/UDP connections to it.
 * Since only the L's transport addresses in the payload need to be translated,
 * it is sufficient to examine only the outbound packets.
 *
 * 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_h245_msg(Ip_u8 *appdata,
                         int    applen,
                         Ipnet_nat_proxy_param *param)
{
    Ipnet_nat_proxy_tuple proxy_tuple;
    Ip_u8   *data, *data_start;
    Ip_u16  port;
    Ip_u32  local_address, ip_addr;
    int     data_length;
    Ip_bool mod = IP_FALSE;

    if (param->incoming == IP_TRUE)
        return 0;
    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;    /* L's local ip */

    /* search for L's ip address in the H.245 payload for all possible
      TCP/UDP connections that may be negotiated.  For each one found, create
      create a static TCP/UDP control block to get the translated transport address.
      We must do this for all L's ip address found in the H.245 payload
      since we are not decoding the ASN.1 message thus don't really know
      which ones will actually be used.  A check is made to prevent creation
      of duplicate bind entries.  The ID of each created static entry is recorded
      so the ALG can delete them when the Netmeeting session is terminated */

    while ((data + 6) <= (data_start + data_length))
    {
        ip_addr = IP_GET_NTOHL(data);

        /* look for L's global address match */
        if (ip_addr == local_address)
        {
            port = IP_GET_NTOHS(data + 4);
            if (port > IPNET_NAT_H323_LOWER_EPHEMERAL_PORT_VALUE)
            {
                IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h245_msg() :: Local host address found in H245 payload. "
                                  "ip = 0x%08x, port = %d", ip_addr, port);

                /* Do not add a mapping for the TCP T1.120 port here. Should be taken care of by NAT rules */
                if (port != IPNET_NAT_T1_120_PORT)
                {
                    /* create a bind entry for this transport address if it hasn't been created yet */
                    ipcom_memset(&proxy_tuple, 0, sizeof(proxy_tuple));
                    proxy_tuple.protocol     = IP_IPPROTO_UDP;
                    proxy_tuple.private_addr = local_address;
                    proxy_tuple.private_port = port;
                    proxy_tuple.public_addr  = param->tuple.public_addr;
                    if (ipnet_nat_proxy_add_mapping(&proxy_tuple,
                                                    IPNET_NAT_H323_MEDIA_TIMEOUT,
                                                    param->mapping,
                                                    IP_FALSE,         /* NAT port = local source port */
                                                    IP_TRUE,          /* Inbound session */
                                                    IP_NULL,
                                                    IP_NULL) < 0)
                    {
                        IPCOM_LOG2(ERR, "ipnet_nat_proxy_h245_msg() :: Failed to add mapping for address = 0x%08x, port = %d",
                                         local_address, port);
                    }
                    else
                    {
                        IPCOM_LOG2(DEBUG, "ipnet_nat_proxy_h245_msg() :: Added mapping for address = 0x%08x, port = %d",
                                           local_address, port);
                    }
                }

                /* Replace L's local address with its global address in the payload */
                IP_SET_HTONL(data, param->nat_addr);
                data += 6;
                mod = IP_TRUE;

                IPCOM_LOG1(DEBUG, "ipnet_nat_proxy_h245_msg() :: "
                                  "Translated local address is (0x%08x)",
                                  param->nat_addr);
            }
            else    /* detected port number is not a valid ephemeral port value */
            {
                IPCOM_LOG1(INFO, "ipnet_nat_proxy_h245_msg() :: detected port invalid, ignore! port = %d", port);
                data++;
            }
        }
        else    /* ip_addr != local_address */
        {
            data++;
        }
    }   /* end while loop */

    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;
}