Beispiel #1
0
void tcpdemux::process_ip6(const struct timeval &ts,const u_char *data, const uint32_t caplen, const int32_t vlan)
{
    const struct private_ip6_hdr *ip_header = (struct private_ip6_hdr *) data;
    u_int16_t ip_payload_len;

    /* make sure that the packet is at least as long as the IPv6 header */
    if (caplen < sizeof(struct private_ip6_hdr)) {
        DEBUG(6) ("received truncated IPv6 datagram!");
        return;
    }


    /* for now we're only looking for TCP; throw away everything else */
    if (ip_header->ip6_nxt != IPPROTO_TCP) {
        DEBUG(50) ("got non-TCP frame -- IP proto %d", ip_header->ip6_nxt);
        return;
    }

    ip_payload_len = ntohs(ip_header->ip6_plen);

    /* make sure there's some data */
    if (ip_payload_len == 0) {
        DEBUG(6) ("received truncated IP datagram!");
        return;
    }

    /* do TCP processing */

    process_tcp(ts,
                data + sizeof(struct private_ip6_hdr),
                ip_payload_len,
                ipaddr(ip_header->ip6_src.s6_addr),
                ipaddr(ip_header->ip6_dst.s6_addr),
                vlan,AF_INET6);
}
Beispiel #2
0
/**
 * Fetch the request parameters
 * @param Parrot_PMC i The interpreter
 * @param request_rec * r The request
 * @return Parrot_PMC hash  
 **/
Parrot_PMC mod_parrot_request_parameters(Parrot_PMC interp, request_rec * req) {
    Parrot_PMC hash;
    /* todo, make this non-nasty. although it works */
	hash = mod_parrot_hash_new(interp);
	
	mod_parrot_hash_put(interp, hash, "REQUEST_METHOD", (char*)req->method);
	mod_parrot_hash_put(interp, hash, "REQUEST_URI", req->unparsed_uri);
	mod_parrot_hash_put(interp, hash, "QUERY_STRING", req->args ? req->args : ""); 
	mod_parrot_hash_put(interp, hash, "HTTP_HOST", (char*)req->hostname);
    mod_parrot_hash_put(interp, hash, "SCRIPT_NAME", req->filename);
    mod_parrot_hash_put(interp, hash, "PATH_INFO", req->path_info);
	mod_parrot_hash_put(interp, hash, "SERVER_NAME", req->server->server_hostname);
	mod_parrot_hash_put(interp, hash, "SERVER_PROTOCOL", req->protocol);

	/* Network parameters. This should be simpler, but it isn't. */
	mod_parrot_hash_put(interp, hash, "SERVER_ADDR", ipaddr(req->connection->local_addr));
	mod_parrot_hash_put(interp, hash, "SERVER_PORT", 
             apr_itoa(req->pool, req->connection->local_addr->port));

	mod_parrot_hash_put(interp, hash, "REMOTE_ADDR", 
             ipaddr(req->connection->remote_addr));
	mod_parrot_hash_put(interp, hash, "REMOTE_PORT", 
             apr_itoa(req->pool, req->connection->remote_addr->port));

    if(req->server->server_admin) /* I don't believe this is ever NULL */
		mod_parrot_hash_put(interp, hash, "SERVER_ADMIN", req->server->server_admin);
    return hash;
}
Beispiel #3
0
void tcpdemux::process_ip4(const struct timeval &ts,const u_char *data, uint32_t caplen,int32_t vlan)
{
    const struct ip *ip_header = (struct ip *) data;
    u_int ip_header_len;
    u_int ip_total_len;

    /* make sure that the packet is at least as long as the min IP header */
    if (caplen < sizeof(struct ip)) {
        DEBUG(6) ("received truncated IP datagram!");
        return;
    }

    DEBUG(100)("process_ip4. caplen=%d vlan=%d  ip_p=%d",(int)caplen,(int)vlan,(int)ip_header->ip_p);

    /* for now we're only looking for TCP; throw away everything else */
    if (ip_header->ip_p != IPPROTO_TCP) {
        DEBUG(50) ("got non-TCP frame -- IP proto %d", ip_header->ip_p);
        return;
    }

    /* check and see if we got everything.  NOTE: we must use
     * ip_total_len after this, because we may have captured bytes
     * beyond the end of the packet (e.g. ethernet padding).
     */
    ip_total_len = ntohs(ip_header->ip_len);
    if (caplen < ip_total_len) {
        DEBUG(6) ("warning: captured only %ld bytes of %ld-byte IP datagram",
                  (long) caplen, (long) ip_total_len);
    }

    /* XXX - throw away everything but fragment 0; this version doesn't
     * know how to do fragment reassembly.
     */
    if (ntohs(ip_header->ip_off) & 0x1fff) {
        DEBUG(2) ("warning: throwing away IP fragment from X to X");
        return;
    }

    /* figure out where the IP header ends */
    ip_header_len = ip_header->ip_hl * 4;

    /* make sure there's some data */
    if (ip_header_len > ip_total_len) {
        DEBUG(6) ("received truncated IP datagram!");
        return;
    }

    /* do TCP processing, faking an ipv6 address  */
    process_tcp(ts,data + ip_header_len, ip_total_len - ip_header_len,
                ipaddr(ip_header->ip_src.s_addr),
                ipaddr(ip_header->ip_dst.s_addr),
                vlan,AF_INET);
}
Beispiel #4
0
void dump_dhcp_info(dhcp_info *info)
{
    char addr[20], gway[20], mask[20];
    ALOGD("--- dhcp %s (%d) ---",
            dhcp_type_to_name(info->type), info->type);
    strcpy(addr, ipaddr(info->ipaddr));
    strcpy(gway, ipaddr(info->gateway));
    ALOGD("ip %s gw %s prefixLength %d", addr, gway, info->prefixLength);
    if (info->dns1) ALOGD("dns1: %s", ipaddr(info->dns1));
    if (info->dns2) ALOGD("dns2: %s", ipaddr(info->dns2));
    ALOGD("server %s, lease %d seconds",
            ipaddr(info->serveraddr), info->lease);
}
Beispiel #5
0
std::string SocketSpec::str() const
{
	if (isLocal()) {
		return "unix:" + local();
	} else {
		char buf[256];

		if (ipaddr_.family() == IPAddress::V4)
			snprintf(buf, sizeof(buf), "%s:%d", ipaddr().str().c_str(), port());
		else
			snprintf(buf, sizeof(buf), "[%s]:%d", ipaddr().str().c_str(), port());

		return buf;
	}
}
Beispiel #6
0
/*
Show configured IP addresses.
@function ifaddrs
@return information (TABLE)
*/
static int
Fifaddrs(lua_State *L)
{
	struct ifaddrs *ifaddr = {0};
	struct ifaddrs *i = {0};
	int c = 1;

	errno = 0;
	if (0 > getifaddrs(&ifaddr)) return luaX_pusherror(L, "getifaddrs(3) error");
	lua_newtable(L);
	for (i = ifaddr; i != 0 ; i = i->ifa_next) {
		if (i->ifa_addr == 0) {
			continue;
		}
		lua_newtable(L);
		lua_pushstring(L, i->ifa_name);
		lua_setfield(L, -2, "interface");
		if (i->ifa_addr->sa_family == AF_INET || i->ifa_addr->sa_family == AF_INET6) {
			ipaddr(L, i);
		}
		if (i->ifa_data && (i->ifa_addr->sa_family == AF_PACKET)) {
			ifstats(L, i);
		}
		lua_rawseti(L, -2, c++);
	}
	freeifaddrs(ifaddr);
	return 1;
}
/** \brief callback notified by host2ip_t when the result is known
 */
bool	ipcountry_t::neoip_host2ip_cb(void *cb_userptr, host2ip_vapi_t &cb_host2ip_vapi
						, const inet_err_t &inet_err
						, const std::vector<ip_addr_t> &result_arr)	throw()
{
	// display the result
	KLOG_DBG("enter host2ip returned err=" << inet_err << " with " << result_arr.size() << " ip_addr_t"
					<< " for hostname=" << host2ip->hostname());
	// if the host2ip failed to return an ip address, notify the caller
	if( inet_err.failed() || result_arr.empty() ){
		std::string	reason("unable to resolve the ip_addr_t " + ipaddr().to_string());
		return notify_callback(inet_err_t(inet_err_t::ERROR, reason), std::string());
	}
	
	// create an alias on the result_ipaddr
	const ip_addr_t	result_ipaddr	= result_arr[0]; 
	// log to debug
	KLOG_DBG("result=" << result_ipaddr);
	
	// convert the result_ipaddr into a country code
	const char * country_ptr	= ipaddr2countrycode(result_ipaddr);
	if( !country_ptr ){
		std::string	reason("Internal error. the return ip_addr_t is NOT a ISO3166 code. ip_addr=" + result_ipaddr.to_string());
		return notify_callback(inet_err_t(inet_err_t::ERROR, reason), std::string());
	}
	// notify the caller of the successfull result
	std::string	country_code	= country_ptr;
	return notify_callback(inet_err_t::OK, country_code);
}
Beispiel #8
0
// unix:/var/run/x0d.sock
// [3ffe:1337::2691:1]:8080
SocketSpec SocketSpec::fromString(const std::string& value)
{
	size_t slen = value.size();
	if (slen == 0)
		return SocketSpec();

	if (value.find("unix:") == 0)
		return SocketSpec::fromLocal(value.substr(5));

	if (value[0] == '[') { // IPv6
		auto e = value.find("]");
		if (e == std::string::npos)
			return SocketSpec();

		if (e + 1 <= slen)
			return SocketSpec();

		if (value[e + 1] != ':')
			return SocketSpec();

		std::string ipaddr(value.substr(1, e - 1));
		std::string port(value.substr(e + 2));

		return SocketSpec::fromInet(IPAddress(ipaddr), std::atoi(port.c_str()));
	}

	auto e = value.find(':');

	if (e <= slen)
		return SocketSpec();

	std::string ipaddr(value.substr(1, e - 1));
	std::string port(value.substr(e + 2));

	return SocketSpec::fromInet(IPAddress(ipaddr), std::atoi(port.c_str()));
}
Beispiel #9
0
Client::Client(SOCKET s, SOCKET c, sockaddr_in cs, RCON* r)
{
	this->_rcon = r;
	ssock = s;
	csock = c;
	clientsock = new sockaddr_in();
	*clientsock = cs;
	this->isConnected = true;
	this->sockthread = new std::thread(Client::Loop, this);
	this->sockthread->detach();
	VCMP_PF->LogMessage("[RCON]: A client has connected! (IP: %s)", ipaddr(this).c_str());
	char* version = new char[20];
	GetRVersion(version);
	this->Sendex("VCMP-RCON v%s", version);
	delete version;
	this->isIdentified = false;
}
Beispiel #10
0
bool PeerAddressUtil::ParseAddress( PEER_ADDRESS& addr, const string& s )
{
	std::vector<string> res;
	boost::split( res, s, boost::is_any_of( ":" ), boost::token_compress_on );
	if ( res.size() != 3 )
		return false;
	IPAddress ipaddr( res[0].c_str() );
	UINT16 tcpPort = numeric<UINT16>::parse( res[1], 0 );
	UINT16 udpPort = numeric<UINT16>::parse( res[2], 0 );
	if ( ipaddr.IsInvalidClient() || 0 == tcpPort || 0 == udpPort )
	{
		return false;
	}
	addr.IP = ipaddr.GetAddress();
	addr.TcpPort = tcpPort;
	addr.UdpPort = udpPort;
	return true;
}
void dump_dhcp_info(dhcp_info *info)
{
    char addr[20], gway[20], mask[20];
    LOGD("--- dhcp %s (%d) ---",
            dhcp_type_to_name(info->type), info->type);
    strcpy(addr, ipaddr(info->ipaddr));
    strcpy(gway, ipaddr(info->gateway));
    strcpy(mask, ipaddr(info->netmask));
    LOGD("ip %s gw %s mask %s", addr, gway, mask);
    if (info->dns1) LOGD("dns1: %s", ipaddr(info->dns1));
    if (info->dns2) LOGD("dns2: %s", ipaddr(info->dns2));
    LOGD("server %s, lease %d seconds",
            ipaddr(info->serveraddr), info->lease);
}
Beispiel #12
0
/** \brief Start the operation
 */
inet_err_t	ipcountry_t::start(const ip_addr_t &m_ipaddr, ipcountry_cb_t *callback, void *userptr)	throw()
{
	// copy the parameter
	this->m_ipaddr	= m_ipaddr;
	this->callback	= callback;
	this->userptr	= userptr;

	// build the hostname to resolve - ip_addr_t in reverse order appended with .zz.countries.nerd.dk
	std::string	hostname;
	hostname	= ip_addr_t(NEOIP_HTONL(ipaddr().get_v4_addr())).to_string();
	hostname	+= ".zz.countries.nerd.dk";

	// log to debug
	KLOG_DBG("try to resolve hostname=" << hostname);

	// launch the host2ip_t on the just built hostname
	inet_err_t	inet_err;
	host2ip		= nipmem_new host2ip_t();
	inet_err	= host2ip->start(hostname, this, NULL);
	if( inet_err.failed() )		return inet_err;

	// return no error
	return inet_err_t::OK;
}
Beispiel #13
0
int dump_interface(const char *name)
{
    unsigned addr, flags;
    unsigned char hwbuf[ETH_ALEN];
    int prefixLength;

    if(ifc_get_info(name, &addr, &prefixLength, &flags)) {
        return 0;
    }

    printf("%-8s %s  ", name, flags & 1 ? "UP  " : "DOWN");
    printf("%40s", ipaddr(addr));
    printf("/%-4d", prefixLength);
    printf("0x%08x ", flags);
    if (!ifc_get_hwaddr(name, hwbuf)) {
        int i;
        for(i=0; i < (ETH_ALEN-1); i++)
            printf("%02x:", hwbuf[i]);
        printf("%02x\n", hwbuf[i]);
    } else {
        printf("\n");
    }
    return 0;
}
Beispiel #14
0
void server_exec(Socket server, SockAddrIn server_addr, ClientSet* clients,
                 NoticeBoard* board)
{
    int i;

    if (listen(server, 5) == -1) {
        error("Could not listen on socket");
        exit(1);
    }

    while (running) {
        usleep(100000);
        /* -- Accepting connections -- */
        socklen_t sz = sizeof(server_addr);
        Socket new_socket = accept(server, (SockAddr*)&server_addr, &sz);
        /* Error handling, most likely EAGAIN since we're using
         * non blocking sockets.
         */
        if (new_socket == -1) {
            if (errno != EAGAIN) {
                error("Could not accept connection");
            }
        } else {
            int j = 0;
            fcntl(new_socket, F_SETFL, O_NONBLOCK);
            Client* c = ClientSet_Add(clients, new_socket);
            if (c == NULL) continue;
            memset(c->properties.nick, 0, NICK_MAXLEN);
            strcpy(c->properties.nick, "user");

            for (i = 0; i < clients->size; i++) {
                if (&clients->clients[i] == c ||
                    clients->clients[i].state == DISCONNECTED) continue;
                if (!strcmp(clients->clients[i].properties.nick,
                    c->properties.nick)) {
                    j++;
                    sprintf(c->properties.nick, "user(%d)", j);
                    i = 0;
                }
            }

            SockAddr peer_address;
            socklen_t addrlen = sizeof(peer_address);
            int has_error = getpeername(new_socket, &peer_address,
                                &addrlen);
            if (has_error == -1) {
                error("Error getting peer name");
            }
            SockAddrIn *addr_in = (struct sockaddr_in *)&peer_address;
            c->ip_string = ipaddr(*addr_in);

            printf("Client connected (%s)\n", c->ip_string);
            send_motd(c);
        }

        /* -- Reading data -- */
        for (i = 0; i < clients->size; i++) {
            if (clients->clients[i].state == DISCONNECTED) {
                Client_Destroy(&clients->clients[i]);
                continue;
            }
            client_exec(&(clients->clients[i]), i, clients, board);
        }
    }
}
Beispiel #15
0
/**************************************************************************************************
	CONF_SET_RECURSIVE
	If the 'recursive' configuration option was specified, set the recursive server.
**************************************************************************************************/
static void
conf_set_recursive(void) {
    char		*c;
    const char	*address = conf_get(&Conf, "recursive", NULL);
    char		addr[512];
    int		port = 53;

    if (!address || !address[0])
        return;
    strncpy(addr, address, sizeof(addr)-1);

#if HAVE_IPV6
    if (is_ipv6(addr)) {		/* IPv6 - treat '+' as port separator */
        recursive_family = AF_INET6;
        if ((c = strchr(addr, '+'))) {
            *c++ = '\0';
            if (!(port = atoi(c)))
                port = 53;
        }
        if (inet_pton(AF_INET6, addr, &recursive_sa6.sin6_addr) <= 0) {
            Warnx("%s: %s", address, _("invalid network address for recursive server"));
            return;
        }
        recursive_sa6.sin6_family = AF_INET6;
        recursive_sa6.sin6_port = htons(port);
        forward_recursive = 1;
#if DEBUG_ENABLED && DEBUG_CONF
        DebugX("conf", 1,_("recursive forwarding service through %s:%u"),
               ipaddr(AF_INET6, &recursive_sa6.sin6_addr), port);
#endif
        recursive_fwd_server = STRDUP(address);
    } else {			/* IPv4 - treat '+' or ':' as port separator  */
#endif
        recursive_family = AF_INET;
        if ((c = strchr(addr, '+')) || (c = strchr(addr, ':'))) {
            *c++ = '\0';
            if (!(port = atoi(c)))
                port = 53;
        }
        if (inet_pton(AF_INET, addr, &recursive_sa.sin_addr) <= 0) {
            Warnx("%s: %s", address, _("invalid network address for recursive server"));
            return;
        }
        recursive_sa.sin_family = AF_INET;
        recursive_sa.sin_port = htons(port);
#if DEBUG_ENABLED &&DEBUG_CONF
        DebugX("conf", 1,_("recursive forwarding service through %s:%u"),
               ipaddr(AF_INET, &recursive_sa.sin_addr), port);
#endif
        forward_recursive = 1;
        recursive_fwd_server = STRDUP(address);
#if HAVE_IPV6
    }
#endif

    if (!forward_recursive) return;

    recursion_timeout = atou(conf_get(&Conf, "recursive-timeout", NULL));
    recursion_connect_timeout = atou(conf_get(&Conf, "recursive-connect-timeout", NULL));
    recursion_retries = atou(conf_get(&Conf, "recursive-retries", NULL));
    recursion_algorithm = conf_get(&Conf, "recursive-algorithm", NULL);

}
Beispiel #16
0
  Object* IO::socket_read(STATE, Fixnum* bytes, Fixnum* flags, Fixnum* type) {
    char buf[1024];
    socklen_t alen = sizeof(buf);
    size_t size = (size_t)bytes->to_native();

    String* buffer = String::create_pinned(state, bytes);

    OnStack<1> variables(state, buffer);

    ssize_t bytes_read;
    native_int t = type->to_native();

  retry:
    state->vm()->interrupt_with_signal();
    state->vm()->thread()->sleep(state, cTrue);

    {
      UnmanagedPhase unmanaged(state);

      bytes_read = recvfrom(descriptor(state),
                            (char*)buffer->byte_address(), size,
                            flags->to_native(),
                            (struct sockaddr*)buf, &alen);
    }

    state->vm()->thread()->sleep(state, cFalse);
    state->vm()->clear_waiter();

    buffer->unpin();

    if(bytes_read == -1) {
      if(errno == EINTR) {
        if(state->vm()->thread_interrupted_p(state)) return NULL;
        ensure_open(state);
        goto retry;
      } else {
        Exception::raise_errno_error(state, "read(2) failed");
      }

      return NULL;
    }

    buffer->num_bytes(state, Fixnum::from(bytes_read));

    if(t == 0) return buffer; // none

    Array* ary = Array::create(state, 2);
    ary->set(state, 0, buffer);

    switch(type->to_native()) {
    case 1: // ip
      // Hack from MRI:
      // OSX doesn't return a 'from' result from recvfrom for connection-oriented sockets
      if(alen && alen != sizeof(buf)) {
        ary->set(state, 1, ipaddr(state, (struct sockaddr*)buf, alen));
      } else {
        ary->set(state, 1, cNil);
      }
      break;
#ifndef RBX_WINDOWS
    case 2: // unix
      ary->set(state, 1, unixaddr(state, (struct sockaddr_un*)buf, alen));
      break;
#endif
    default:
      ary->set(state, 1, String::create(state, buf, alen));
    }

    return ary;
  }
Beispiel #17
0
/* Embedded code is not funny at all... */
int
mib_instance_search(struct oid_search_res *ret_oid)
{
  int i;
  Variable *var = &ret_oid->var;
  lua_State *L = mib_lua_state;

  /* Empty lua stack. */
  lua_pop(L, -1);
  /* Get function. */
  lua_rawgeti(L, LUA_ENVIRONINDEX, ret_oid->callback);
  /* op */
  lua_pushinteger(L, ret_oid->request);
  /* req_sub_oid */
  lua_newtable(L);
  for (i = 0; i < ret_oid->inst_id_len; i++) {
    lua_pushinteger(L, ret_oid->inst_id[i]);
    lua_rawseti(L, -2, i + 1);
  }

  if (ret_oid->request == MIB_REQ_SET) {
    /* req_val */
    switch (tag(var)) {
      case ASN1_TAG_INT:
        lua_pushinteger(L, integer(var));
        break;
      case ASN1_TAG_OCTSTR:
        lua_pushlstring(L, octstr(var), length(var));
        break;
      case ASN1_TAG_CNT:
        lua_pushnumber(L, count(var));
        break;
      case ASN1_TAG_IPADDR:
        lua_pushlstring(L, (char *)ipaddr(var), length(var));
        break;
      case ASN1_TAG_OBJID:
        lua_newtable(L);
        for (i = 0; i < length(var); i++) {
          lua_pushnumber(L, oid(var)[i]);
          lua_rawseti(L, -2, i + 1);
        }
        break;
      case ASN1_TAG_GAU:
        lua_pushnumber(L, gauge(var));
        break;
      case ASN1_TAG_TIMETICKS:
        lua_pushnumber(L, timeticks(var));
        break;
      default:
        lua_pushnil(L);
        break;
    }
    /* req_val_type */
    lua_pushinteger(L, tag(var));
  } else {
    /* req_val */
    lua_pushnil(L);
    /* req_val_type */
    lua_pushnil(L);
  }

  if (lua_pcall(L, 4, 4, 0) != 0) {
    SMARTSNMP_LOG(L_ERROR, "MIB search hander %d fail: %s\n", ret_oid->callback, lua_tostring(L, -1));
    tag(var) = ASN1_TAG_NO_SUCH_OBJ;
    return 0;
  }

  ret_oid->err_stat = lua_tointeger(L, -4);
  tag(var) = lua_tonumber(L, -1);

  if (!ret_oid->err_stat && MIB_TAG_VALID(tag(var))) {
    /* Return value */
    if (ret_oid->request != MIB_REQ_SET) {
      switch (tag(var)) {
        case ASN1_TAG_INT:
          length(var) = 1;
          integer(var) = lua_tointeger(L, -2);
          break;
        case ASN1_TAG_OCTSTR:
          length(var) = lua_objlen(L, -2);
          memcpy(octstr(var), lua_tostring(L, -2), length(var));
          break;
        case ASN1_TAG_CNT:
          length(var) = 1;
          count(var) = lua_tonumber(L, -2);
          break;
        case ASN1_TAG_IPADDR:
          length(var) = lua_objlen(L, -2);
          for (i = 0; i < length(var); i++) {
            lua_rawgeti(L, -2, i + 1);
            ipaddr(var)[i] = lua_tointeger(L, -1);
            lua_pop(L, 1);
          }
          break;
        case ASN1_TAG_OBJID:
          length(var) = lua_objlen(L, -2);
          for (i = 0; i < length(var); i++) {
            lua_rawgeti(L, -2, i + 1);
            oid(var)[i] = lua_tointeger(L, -1);
            lua_pop(L, 1);
          }
          break;
        case ASN1_TAG_GAU:
          length(var) = 1;
          gauge(var) = lua_tonumber(L, -2);
          break;
        case ASN1_TAG_TIMETICKS:
          length(var) = 1;
          timeticks(var) = lua_tonumber(L, -2);
          break;
        default:
          assert(0);
      }
    }

    /* For GETNEXT request, return the new oid */
    if (ret_oid->request == MIB_REQ_GETNEXT) {
      ret_oid->inst_id_len = lua_objlen(L, -3);
      for (i = 0; i < ret_oid->inst_id_len; i++) {
        lua_rawgeti(L, -3, i + 1);
        ret_oid->inst_id[i] = lua_tointeger(L, -1);
        lua_pop(L, 1);
      }
    }
  }

  return ret_oid->err_stat;
}
void dump_dhcp_msg(dhcp_msg *msg, int len)
{
    unsigned char *x;
    unsigned int n,c;
    int optsz;
    const char *name;
    char buf[2048];

    LOGD("===== DHCP message:");
    if (len < DHCP_MSG_FIXED_SIZE) {
        LOGD("Invalid length %d, should be %d", len, DHCP_MSG_FIXED_SIZE);
        return;
    }

    len -= DHCP_MSG_FIXED_SIZE;

    if (msg->op == OP_BOOTREQUEST)
        name = "BOOTREQUEST";
    else if (msg->op == OP_BOOTREPLY)
        name = "BOOTREPLY";
    else
        name = "????";
    LOGD("op = %s (%d), htype = %d, hlen = %d, hops = %d",
           name, msg->op, msg->htype, msg->hlen, msg->hops);
    LOGD("xid = 0x%08x secs = %d, flags = 0x%04x optlen = %d",
           ntohl(msg->xid), ntohs(msg->secs), ntohs(msg->flags), len);
    LOGD("ciaddr = %s", ipaddr(msg->ciaddr));
    LOGD("yiaddr = %s", ipaddr(msg->yiaddr));
    LOGD("siaddr = %s", ipaddr(msg->siaddr));
    LOGD("giaddr = %s", ipaddr(msg->giaddr));

    c = msg->hlen > 16 ? 16 : msg->hlen;
    hex2str(buf, msg->chaddr, c);
    LOGD("chaddr = {%s}", buf);

    for (n = 0; n < 64; n++) {
        if ((msg->sname[n] < ' ') || (msg->sname[n] > 127)) {
            if (msg->sname[n] == 0) break;
            msg->sname[n] = '.';
        }
    }
    msg->sname[63] = 0;

    for (n = 0; n < 128; n++) {
        if ((msg->file[n] < ' ') || (msg->file[n] > 127)) {
            if (msg->file[n] == 0) break;
            msg->file[n] = '.';
        }
    }
    msg->file[127] = 0;

    LOGD("sname = '%s'", msg->sname);
    LOGD("file = '%s'", msg->file);

    if (len < 4) return;
    len -= 4;
    x = msg->options + 4;

    while (len > 2) {
        if (*x == 0) {
            x++;
            len--;
            continue;
        }
        if (*x == OPT_END) {
            break;
        }
        len -= 2;
        optsz = x[1];
        if (optsz > len) break;
        if (x[0] == OPT_DOMAIN_NAME || x[0] == OPT_MESSAGE) {
            if ((unsigned int)optsz < sizeof(buf) - 1) {
                n = optsz;
            } else {
                n = sizeof(buf) - 1;
            }
            memcpy(buf, &x[2], n);
            buf[n] = '\0';
        } else {
            hex2str(buf, &x[2], optsz);
        }
        if (x[0] == OPT_MESSAGE_TYPE)
            name = dhcp_type_to_name(x[2]);
        else
            name = NULL;
        LOGD("op %d len %d {%s} %s", x[0], optsz, buf, name == NULL ? "" : name);
        len -= optsz;
        x = x + optsz + 2;
    }
}