I'm programming for a device running Linux OS.
The device runs ping command to youtube.com successfully. However, in source code, if I call gethostbyname("youtube.com"), the function returns NULL.
UPDATE LOG
My code looks like this (this is just a short pseudo code to describe my issue, not full code)
void my_func()
{
struct hostent *hostEntry;
hostEntry = gethostbyname("youtube.com");
if (hostEntry) {
// gethostbyname() resolve host name successfully, no need to care
} else {
printf("Fail to get host, herrno=%d, strErr=%s\n", h_errno, hstrerror(h_errno));
}
}
And the device's output when gethostbyname() returns NULL is
Fail to get host, herrno=1, strErr=Unknown host
This is the device's output when I exit the program and run ping youtube.com
$ ping youtube.com
PING youtube.com (64.233.189.91): 56 data bytes
64 bytes from 64.233.189.91: seq=0 ttl=55 time=57.824 ms
64 bytes from 64.233.189.91: seq=1 ttl=55 time=56.306 ms
64 bytes from 64.233.189.91: seq=2 ttl=55 time=56.790 ms
64 bytes from 64.233.189.91: seq=3 ttl=55 time=56.831 ms
64 bytes from 64.233.189.91: seq=4 ttl=55 time=56.417 ms
What should I check now?
I add res_init() to resolve this issue and fortunately, it works.
#include <resolv.h>
void my_func()
{
struct hostent *hostEntry;
hostEntry = gethostbyname("youtube.com");
if (hostEntry) {
res_init();
hostEntry = gethostbyname("youtube.com");
}
if (hostEntry) {
// gethostbyname() resolve host name successfully, no need to care
} else {
printf("Fail to get host, herrno=%d, strErr=%s\n", h_errno, hstrerror(h_errno));
}
}
This may be the reason why the function helps
The res_init() function reads the configuration files (see resolv.conf(5)) to get the default domain name, search order and name server address(es).
Related
I'm currently using esp32 to stream audio, using librtmp, idf-v4.3 library. librtmp works fine when I use espressif/arduino-esp32 library, but get a lot of stack overflow errors when using espressif/esp-idf , whether to put librtmp in Internal SRAM or External SRAM.
I found through debugging that the problem probably occurred in the socket send() function:
int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
{
int rc;
#ifdef _DEBUG
fwrite(buf, 1, len, netstackdump);
#endif
#if defined(CRYPTO) && !defined(NO_SSL)
if (sb->sb_ssl)
{
rc = TLS_write(sb->sb_ssl, buf, len);
}
else
#endif
{
printf("socket send:%p len:%d heap:%d\n", buf, len, esp_get_free_internal_heap_size());
rc = send(sb->sb_socket, buf, len, 0);
printf("socket send return\n");
}
return rc;
}
The error is as follows:
I (559) wifi:wifi driver task: 3ffc0744, prio:23, stack:6656, core=0
I (639) wifi_init: tcp mss: 1440
I (639) wifi_init: WiFi IRAM OP enabled
I (639) wifi_init: WiFi RX IRAM OP enabled
I (649) phy_init: phy_version 4670,719f9f6,Feb 18 2021,17:07:07
I (759) wifi:mode : sta (34:ab:95:77:59:e0)
I (759) wifi:enable tsf
I (759) wifi station: wifi_init_sta finished.
I (799) wifi:new:<6,1>, old:<1,0>, ap:<255,255>, sta:<6,1>, prof:1
I (799) wifi:state: init -> auth (b0)
I (809) wifi:state: auth -> assoc (0)
I (809) wifi:state: assoc -> run (10)
I (939) wifi:connected with TIMO_1, aid = 2, channel 6, 40U, bssid = 88:25:93:1a:41:64
I (939) wifi:security: WPA2-PSK, phy: bgn, rssi: -59
I (939) wifi:pm start, type: 1
W (949) wifi:<ba-add>idx:0 (ifx:0, 88:25:93:1a:41:64), tid:0, ssn:0, winSize:64
I (999) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (1549) esp_netif_handlers: sta ip: 192.168.0.102, mask: 255.255.255.0, gw: 192.168.0.1
I (1549) wifi station: got ip:192.168.0.102
I (1549) wifi station: connected to ap SSID:TIMO_1 password:********
into rtmp_connect
into RTMP_Connect0
into RTMP_Connect1
socket send:0x3ffb9e99 len:1537 heap:216508
***ERROR*** A stack overflow in task main has been detected.
Backtrace:0x400819e6:0x3ffb9b000x40088341:0x3ffb9b20 0x4008b802:0x3ffb9b40 0x40089fc6:0x3ffb9bc0 0x40088440:0x3ffb9be0 0x400883f2:0x0000000c |<-CORRUPTED
0x400819e6: panic_abort at C:/Users/q1004/esp/esp-idf/components/esp_system/panic.c:402
0x40088341: esp_system_abort at C:/Users/q1004/esp/esp-idf/components/esp_system/esp_system.c:121
0x4008b802: vApplicationStackOverflowHook at C:/Users/q1004/esp/esp-idf/components/freertos/port/xtensa/port.c:394
0x40089fc6: vTaskSwitchContext at C:/Users/q1004/esp/esp-idf/components/freertos/tasks.c:3505
0x40088440: _frxt_dispatch at C:/Users/q1004/esp/esp-idf/components/freertos/port/xtensa/portasm.S:436
0x400883f2: _frxt_int_exit at C:/Users/q1004/esp/esp-idf/components/freertos/port/xtensa/portasm.S:231
Has anyone had the same problem, I will put the whole project on github. help.
Looks like you're getting a stack overflow in the main task.
Try increasing the main task stack size:
make menuconfig -> Component Config -> ESP System settings -> Main task stack size
The relevant sdkconfig setting is CONFIG_ESP_MAIN_TASK_STACK_SIZE (formerly CONFIG_MAIN_TASK_STACK_SIZE).
Also important to read: Reducing Stack Sizes.
So I wanted to put a few printk messages in ip_rcv function to see whether after receiving a packet from a particular IP there is a message printed. I am attaching the entire ip_rcv function which has the printk modifications:
int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
{
const struct iphdr *iph;
struct net *net;
u32 len;
/* When the interface is in promisc. mode, drop all the crap
* that it receives, do not try to analyse it.
*/
if (skb->pkt_type == PACKET_OTHERHOST)
goto drop;
net = dev_net(dev);
__IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len);
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb) {
__IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS);
goto out;
}
if (!pskb_may_pull(skb, sizeof(struct iphdr)))
goto inhdr_error;
iph = ip_hdr(skb);
//**PSK's Modification**
if (iph->saddr == 0x08080808)
printk("\n***PSK: %x IP's message recieved: Google***\n", iph->saddr);
if (iph->saddr == 0x0202000A)
printk("\n***PSK: %x IP's message recieved: Gateway***\n", iph->saddr);
if (iph->saddr == 0x010000FF)
printk("\n***PSK: %x IP's message recieved : Home***\n", iph->saddr);
/* RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum.
*
* Is the datagram acceptable?
*
* 1. Length at least the size of an ip header
* 2. Version of 4
* 3. Checksums correctly. [Speed optimisation for later, skip loopback checksums]
* 4. Doesn't have a bogus length
*/
if (iph->ihl < 5 || iph->version != 4)
goto inhdr_error;
BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1);
BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0);
BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE);
__IP_ADD_STATS(net,
IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK),
max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
if (!pskb_may_pull(skb, iph->ihl*4))
goto inhdr_error;
iph = ip_hdr(skb);
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
goto csum_error;
len = ntohs(iph->tot_len);
if (skb->len < len) {
__IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS);
goto drop;
} else if (len < (iph->ihl*4))
goto inhdr_error;
/* Our transport medium may have padded the buffer out. Now we know it
* is IP we can trim to the true length of the frame.
* Note this now means skb->len holds ntohs(iph->tot_len).
*/
if (pskb_trim_rcsum(skb, len)) {
__IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS);
goto drop;
}
iph = ip_hdr(skb);
skb->transport_header = skb->network_header + iph->ihl*4;
/* Remove any debris in the socket control block */
memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
IPCB(skb)->iif = skb->skb_iif;
/* Must drop socket now because of tproxy. */
skb_orphan(skb);
return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING,
net, NULL, skb, dev, NULL,
ip_rcv_finish);
csum_error:
__IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS);
inhdr_error:
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
drop:
kfree_skb(skb);
out:
return NET_RX_DROP;
}
I should get a message printed into the kernel buffer after getting a packet from either Google DNS, my local gateway (10.0.2.2) or loop-back address (127.0.0.1). This is working fine for the DNS and the gateway, but not when I ping localhost or try to run a program which involves back and forth from a localhost. Are there some other kernel function calls that specifically handle packets to localhost, or am I missing something very basic? I thought the loopback packets should trace the same path through the stack as any other packet at least until L3. I would also appreciate if someone briefly explains the handling of loopback traffic along with the answer.
System Specs:
System- Ubuntu on Virtual Machine
Kernel- 4.15.0-70 generic
I think there is something wrong here:
if (iph->saddr == 0x010000FF)
Perhaps you mean:
if (iph->saddr == 0x0100007F)
loopback packets should trace the same path
Yep, in general.
Investigate more about the details of loopback device.
Also you always can operate with some useful tools like trace-cmd. F.e. to see the function graph you can do:
trace-cmd record -p function_graph -g net_rx_action
Then start ping 127.0.0.1, then stop tracing and watch report like
trace-cmd report | vim -
Here you can see the "path" and ensure that your localhost pinging eventually falls into ip_rcv().
I've got the TCP Echo example working well on my hardware, and yesterday figured out how to get a UDP Broadcast working. After further thought, I've realized is that what I really need is to be able to set up a TCP Connection to a Static IP, the idea being that my hardware can connect to a server of some sort and then use that connection for all its transactions. The difference is that whereas the echo example sets up a passive connection, that binds with the incoming source (as I understand it), I want to initiate the connection deliberately to a known IP.
Based on what I found on Wikia Here Here
I've attempted as a base case to implement a function that can send a packet to a Defined IP. I'm simply trying to send a packet to my PC, and I'm looking for it on Wireshark.
void echo_tx_tcp()
{
err_t wr_err = ERR_OK;
struct tcp_pcb *l_tcp_pcb;
l_tcp_pcb = tcp_new();
ip_addr_t dest_ip =
{ ((u32_t)0x0C0C0C2BUL) };
wr_err = tcp_bind(l_tcp_pcb, &dest_ip, 12);
wr_err = tcp_connect(l_tcp_pcb, &dest_ip, 12, echo_accept);
tcp_sent(l_tcp_pcb, echo_sent);
struct pbuf *p = pbuf_alloc(PBUF_TRANSPORT, 1024, PBUF_RAM);
unsigned char buffer_send[1024] = "My Name Is TCP";
p->payload = buffer_send;
p->len = 1024;
p->tot_len = 1024;
wr_err = tcp_write(l_tcp_pcb, p->payload, p->len, 1);
wr_err = tcp_output(l_tcp_pcb);
if(wr_err == ERR_OK)
{
p->len++;
}
return;
}
The last if statement just exists so that I can inspect the wr_err value with a debugger. The err is coming back OK but the packet is not seen on wireshark. My setup is my hardare as well as my PC connected to a router in an isolated manner. The IP Address of the PC locally is 12.12.12.43
Am I missing a step here?
The tcp_write() function will fail and return ERR_MEM if:
The length of the data exceeds the current send buffer size.
The length of the queue of the outgoing segment is larger than the upper limit defined in lwipopts.h.
The number of bytes available in the output queue can be retrieved with the tcp_sndbuf() function.
Potential solution(s):
Try again but send less data.
Monitor the amount of space available in the send buffer and only send (more) data when there is space available in the send buffer.
Suggestions:
tcp_snd_buf() can be used to find out how much send buffer space is available.
tcp_sent() can be implemented with callback function, that will be called when send butter space is available.
I am writing a kernel module which forms its own packet at ip level and then sends the data . I just want to know how to find the ip address of a local network interface.
There are defined ioctls SIOCGIFADDR (to get if address) and SIOCSIFADDR (to set if address).
All device configuration for IPv4 is done in net/ipv4/devinet.c. You can refer to this source file to get more information.
Wanting to read interface addresses reeks of a design problem. However, if you are looking for determining the preferred source address to use when contacting a remote peer is given in struct rt6_info.rt6i_prefsrc after obtaining it with ip6_route_output. Something along the lines of (with no implied guarantees):
int pick_addr(struct in6_addr *saddr, struct net *net, const struct in6_addr *daddr)
{
struct rt6_info *rt;
struct flowi6 fl6;
int ret;
memset(&fl6, 0, sizeof(fl6));
memcpy(&fl6.daddr, daddr, sizeof(*daddr));
dst = (struct rt6_info *)ip6_route_output(net, NULL /* or sk if you have it */, &fl6);
ret = rt->dst.error;
if (ret == 0)
memcpy(saddr, &rt->rt6i_prefsrc.addr, sizeof(*saddr));
dst_release(&rt->dst);
return ret;
}
We have if_getconfig function available in linux-x.y.z/Documentation/networking/ifenslave.c file which is a very good example of how to use ioctls and fetch address from kernel space
When trying to resolve Facebook's numeric IP address as a test 2620:0:1cfe:face:b00c::3:, if I leave the terminating 0 off the address, inet_pton() barfs. If I put it back on everything works.
Running ubuntu 9.10:
rc = inet_pton(AF_INET6, "2620:0:1cfe:face:b00c::3:0", &ip); -> OK
rc = inet_pton(AF_INET6, "2620:0:1cfe:face:b00c::3:", &ip); -> returns -2
ping6 -n www.v6.facebook.com returns the IP address w/o the trailing 0.
It seems that ping, in it's great wisdom, adds a colon after the IP address like so:
PING maclawran.ca (173.230.128.18) 56(84) bytes of data.
64 bytes from ns.maclawran.ca (173.230.128.18): icmp_seq=1 ttl=51 time=50.3 ms
Of course if you're pinging an IPv6 address, it's already got lots of colons in it:
PING 2620:0:1cfe:face:b00c::3(2620:0:1cfe:face:b00c::3) 56 data bytes
64 bytes from 2620:0:1cfe:face:b00c::3: icmp_seq=1 ttl=52 time=9.44 ms
======================================^ << THANKS PING