getting the domain name by code in Linux - c

I am using getdomainname() and gethostbyname() to try to get the domain of the computer so I can show the correct information on my program. However sometimes these functions don't return the correct information.
Is there any other way (in plain C) to get the domain name in Linux?
Edit: just to make it a bit more clear: I want to check if the computer is part of a domain. If it is, get the domain name.
Currently I am using the functions mentioned above. Are there any others?
#unwind: please DO NOT edit this question for "brevity" if I would like to say thanks I'll say thanks.
Thanks!

If you want to get the (Internet) domain name there are certain issues you need to think about.
A computer can have multiple network interfaces, in fact it almost certainly has at least two including the loopback interface. Each interface has an IP address (possibly more than one) and each IP address can be mapped to from any number of DNS names and entries in the hosts file.
So which, if any of the many possible domain names that getdomainname() returns depends on a whole raft of configuration issues. e.g. which IP address is configured to be the primary address, whether the hosts file is used in preference to DNS, whether the hosts file is correctly configured, whether the IP address has a reverse lookup set and lots of other issues.
For instance, it is fairly common to misconfigure the hosts file. If you see an entry in it like:
192.168.1.1 foohost foohost.example.com
that is wrong. The first host name on a line is the canonical name (for the interface) and subsequent entries are merely aliases. If you want the domain to come out as example.com rather than nothing, it needs to look like this:
192.168.1.1 foohost.example.com foohost
Also, every IP address on the Internet should ideally have a reverse lookup record in DNS which maps the IP address to a hostname and domain. However, there is no rule to say it has to exist or to say that it has to be the domain by which you SSH'd in or pointed your web browser at.
On any given computer, there are many reasons why the domain name is not what you expect.

Unfortunately this information is not always set correctly. First of all, complain to your system administrator.
If all that fails, with something like the following you may get a field res->ai_canonname with a canonical hostname and then also iterate over all IP addresses:
struct addrinfo *res = NULL;
struct addrinfo hints = {
.ai_family = AF_UNSPEC,
.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_CANONNAME | (name ? 0 : AI_PASSIVE),
.ai_socktype = SOCK_STREAM,
};
getaddrinfo(name, NULL, &hints, &res);
for (struct addrinfo *p = res; p; p = p->ai_next) {
...
}
You'd then somehow have to select which ones are interesting for you (avoid loopback etc) and try to find a hostname corresponding to one of these IP addresses. But as IP addresses do not necessarily correspond to a valid hostname, this might fail also.

To get the hostname of the computer you are running the program on:
uname
/etc/hostname

Related

Whats the meaning from the IP Headers in C iph_tos?

Of course, some information are going to be send to the target machine. Something like the IP version and the length... But what does "tos" mean?
­­­­­­­­­­­­­­­­­­­­
From [man]: IP(7):
IP_TOS (since Linux 1.0)
Set or receive the Type-Of-Service (TOS) field that is sent...

C - getaddrinfo returns "Servname not supported for ai_socktype"

So, after I got this error, I've been looking for an answer in here, almost everyone had a difficult way to fix this error but no one explained why this error occurs at all, so I don't find this question to be exactly duplicate.
I wrote a TCP socket in C and I used "getaddrinfo" function to make the socket work with hostnames, well it worked perfectly! you can find my codes on github.
but when I tried to create a UDP socket by "getaddrinfo" I got this error:
Servname not supported for ai_socktype
client.c
const char *host = argv[1];
const char *service = argv[2];
const char *string = argv[3];
struct addrinfo addrCriteria;
memset(&addrCriteria, 0, sizeof(addrCriteria));
addrCriteria.ai_family = AF_UNSPEC;
addrCriteria.ai_socktype = SOCK_DGRAM;
addrCriteria.ai_protocol = IPPROTO_UDP;
struct addrinfo *servAddr;
int ret = getaddrinfo(host, service, &addrCriteria, &servAddr);
if(ret != 0)
sysError(gai_strerror(ret));
I realized that when I give "service" a numeric input like 8080, no errors would return but when I use a string as service name like "tproxy" which points to port/8081, 'gai_strerror' returns mentioned error.
Obviously, gai_strerror says: "service names not supported for 'SOCK_DGRAM' socket types", but why? I mean the exact reason for "getaddrinfo" not supporting name services over UDP sockets?
Is there any other way to use service names with UDP sockets instead of port numbers? how?
TL;DR: There is no tproxy UDP port.
If you look up the tproxy service for UDP sockets in your service database,
getent services tproxy/udp
You get no output, because tproxy is not an UDP service. If you look at all tproxy services regardless of the protocol, getent services | grep -e tproxy, you'll see
tproxy 8081/tcp
which means that tproxy service is only defined for TCP protocol.
This means that if you ask getaddrinfo() for an UDP socket for service 8081, you will not find anything, because tproxy is only defined for TCP and not UDP.
Compare to the case where you ask for and UDP socket for xmpp-client service. At least my service database (getent services xmpp-client/udp) responds with
xmpp-client 5222/udp jabber-client
and indeed, getaddrinfo() happily provides the socket description for such UDP sockets (using xmpp-client or jabber-client as the service).
So, there are services like xmpp-client that do have both TCP and UDP ports defined. On my system, getent services | grep -e xmpp-client shows
xmpp-client 5222/tcp jabber-client
xmpp-client 5222/udp jabber-client
Because TCP and UDP are different protocols over IP, it makes sense that a service could use a different port number for TCP and UDP communications. So, it is unreasonable to assume that the service database should just return the same port numbers for TCP and UDP sockets.
In other words, you encounter the error because you mistakenly assume that because some service uses a TCP port, with a name registered in the service database, you should be able to use that name to specify an UDP port number, too.
TCP and UDP are separate protocols, and their port number spaces are separate. For example, TCP port 512 is used by the Unix exec r-service, whereas UDP port 512 is used by the biff mail notification service.
When a non-numeric value is given for the service parameter, it is looked up (on Linux) in the /etc/services file. This file maps a service name to a port/protocol. Below are some sample entries:
ssh 22/tcp
telnet 23/tcp
domain 53/tcp # name-domain server
domain 53/udp
The reason you're getting an error is because there is no UDP entry in your /etc/services file for "tproxy". Take a look at this file and look for an entry that does specify a UDP port such as "domain". That should have entries for both 53/tcp and 53/udp. If you pass in "domain" as the service name you should get a result back.

Berkeley sockets' passivesock portbase meaning

I am tried to understand the passive socket by tracing the code
http://merkez.ube.ege.edu.tr/~erciyes/ube528/passivesock.c
And I found that the following code
/* Map service name to port number */
if(pse = getservbyname(service, protocol)){
sin.sin_port = htons(ntohs((u_short)pse->s_port) + portbase);
}
else if((sin.sin_port = htons((u_short)atoi(service))) == 0){
errexit("can't get \"%s\" service entry\n", service);
}
I have some question about the htons(ntohs((u_short)pse->s_port) + portbase);
What is the portbase, I found the comment u_short portbase = 0; /* port base, for non-root servers */ but still know what it means?
I have googled it by 'passive socket portbase' but cannot find useful information.
Thx in advance.
Ports below 1024 are system ports and require superuser privileges to access (i.e. root) [1]. As such when running this program as a non root user you may want to remap that port numbers to start at a different base from 0. e.g. by starting at port 1024 no ports will be in the superuser restricted zone (e.g. our well known port 80 will now be 1104). You could choose to map these anywhere.
The comment is the give away:/* port base, for non-root servers */, combined with the fact that this variable is NEVER set anywhere in that file. Only ever is it read. So when using this C library, you are free to set port base before calling any of the functions in order to remap the ports.

Specifying new option for hop by hop extension header IPv6?

I have been trying to get an answer for this for sometime now but not been able to find it.
Is there a way that I can specify a new option value for the hop by hop extension header in IPv6, so that I can parse the value in the user space rather than the kernel parsing it?
The kernel when tries to parse the value, sends me an ICMP reply stating parameter not recognized for that value in the header.
I'm wondering if there should be a way to deploy and test new options in IPv6 extension header without writing handlers for them as LKM.
There isn't a lot available on the web for IPv6, so any help from IPv6 experts would be great!
RFC 2460 mentions this. I assume you can create a new option type for testing any new applications:
Mindful of the need for compatibility with existing IPv6 deployments,
new IPv6 extension headers MUST NOT be created or specified, unless
no existing IPv6 Extension Header can be used by specifying a new
option for that existing IPv6 Extension Header. Any proposal to
create or specify a new IPv6 Extension Header MUST include a detailed
technical explanation of why no existing IPv6 Extension Header can be
used in the Internet-Draft proposing the new IPv6 Extension Header.
As for "The kernel when tries to parse the value, sends me an ICMP reply ..." you mentioned, by "kernel" I assume you means a remote ipv6 node ( either router or destination host ). Then you might set the "Option Type" wrong way in your egress packet sending by raw-socket.
As RFC 2460 says:
The Option Type identifiers are internally encoded such that their highest-order two bits specify the action that must be taken if the processing IPv6 node does not recognize the Option Type:
00, 01, 10, 11 ....
--- I guess you fill in "10" or "11", you could fill in "00"

Linux C: How to know the default interface for internet access?

I want to find out the default network in use. My current method was to find all IP addresses and compare it to the default gateway IP address, but that sounds silly. What is the correct way of doing it ?
UPDATE
I want to use a C program, not by commands ...
You can try a slightly dirtier but infinitely easier approach:
cnicutar#lemon:~$ ip route show to 0.0.0.0/0
default via X.Y.Z.T dev eth0 proto static
^^^^
So you can try:
FILE *cmd = popen("ip route show", "r");
fgets(str, LEN, cmd);
Then you can use strtok, strstr etc.

Resources