DNS Client that is written Using C Sockets - sockets

I just want to write DNS client program using C sockets that
takes three arguments: a query name (e.g., host name or domain name) and a query type (A, or NS, or MX), and DNS server name. Print out the responses in the answer section of the DNS record received.
I know there is a command getaddrinfo..
but I just want to connect to lookup table and then
get the DNS server name...
so when i give the input ./a.out www.google.com A 144.20.190.70
it will show something similar to this:
Server: 144.20.190.70
Address: 144.20.190.70#53
Non-authoritative answer:
Name : www.google.com
Canonical name : www.l.google.com
Name : www.l.google.com
Address : 74.125.19.104
Name : www.l.google.com
Address : 74.125.19.105
Name : www.l.google.com
Address : 74.125.19.106
Name : www.l.google.com
Address : 74.125.19.147
Name : www.l.google.com
Address : 74.125.19.99
Name : www.l.google.com
Address : 74.125.19.103

Yes you need to see Bev.net.dns class that Rob-philpott made for .net
Click Here
building requests to send to DNS servers is not easy but once you can get the answer back from the server then you need to send it back to the browser and this is the bit i've got stuck on.
i listen on port 53/UDP and get the request and send it to the DNS server and get a valid responce but then i send that back to the browser using the remote client port as a UDP but the browser will not except the reply.
Robs code is real easy to use as shown below "Resolver.Lookup" and i just neded to add a bit so that the original byte array sent from the DNS server as saved in Resolver.Message ready to send back to the browser.
public void Listen()
{
receiveSocket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp );
receiveEndPoint = new IPEndPoint(IPAddress.Any, receivePort); receiveSocket.Bind(receiveEndPoint);
receivePort = (receiveSocket.LocalEndPoint as IPEndPoint).Port;
receiveBuffer = new byte[BufferSize];
receiveAsyncResult = receiveSocket.BeginReceiveFrom(receiveBuffer, 0, receiveBuffer.Length, SocketFlags.None, ref receiveEndPoint, new AsyncCallback(NetworkMessageReceivedCallback), receiveSocket);
}
public void NetworkMessageReceivedCallback(IAsyncResult asyncResult)
{
EndPoint remoteEndPoint = null;
byte[] bytes = null;
remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); //Will contain the clients port
int bytesRead = receiveSocket.EndReceiveFrom(asyncResult, ref remoteEndPoint);
bytes = new Byte[bytesRead];
Buffer.BlockCopy(receiveBuffer, 0, bytes, 0, bytesRead);
//string ip = "208.67.222.222";
string ip = "192.168.1.254";
IPAddress dnsServer = IPAddress.Parse(ip);
Response R = Resolver.Lookup(bytes, dnsServer);
receiveSocket.SendTo(R.Message , remoteEndPoint);//127.0.0.1
receiveSocket.Close();
Listen();
}

Related

NetCore IPV6 socket connection fails on linux-arm

I am trying to establish an IPV6 socket connection with net-core 3.0 on a linux-arm platform (raspberry pi).
At the time when I try to bind the socket to the local ethernet adapter an Exception ((22): Invalid argument [fe80::211c:bf90:fbbf:9800]:5400) is thrown.
When i try the same on my windows development machine (with a different link-local ip), everything works fine.
IPV4 socket connection is also possible on both, my windows development machine and on the target linux-arm platform.
To the source code:
I used the socket example of microsoft as a base and changed the IPV4 into an IPV6 address.
The exception is thrown after the "Bind" method.
Here is the client side code:
//definet the target endpoint
IPAddress ipAddress;
IPAddress.TryParse("fe80::211c:bf90:fbbf:9800", out ipAddress);
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5400);
// Create a TCP/IP socket.
Socket sender = new Socket(ipAddress.AddressFamily ,SocketType.Stream, ProtocolType.Tcp);
//bind to the local network interface
IPAddress localIp;
IPAddress.TryParse("fe80::833:e68b:32ee:4c39", out localIp);
EndPoint localEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0);
sender.Bind(localEndPoint);
// Connect the socket to the remote endpoint. Catch any errors.
try
{
sender.Connect(remoteEP);
Console.WriteLine("Socket connected to {0}",
sender.RemoteEndPoint.ToString());
The input of Ron was in fact the missing part. Hence the target endpoint IpAddress has to provided with the ScopeId (NIC Nr).
//definet the target endpoint
IPAddress ipAddress;
IPAddress.TryParse("fe80::211c:bf90:fbbf:9800", out ipAddress);
ipAddress.ScopeId = scopeId;
IPEndPoint remoteEP = new IPEndPoint(ipAddress, 5400);
To the scope ID of the first link local address for example this code can be used:
private static long GetScopeIdForHostLinkLocal()
{
IPAddress firstLinkLocal = null;
var info = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface nic in info)
{
var ipProps = nic.GetIPProperties();
var uniAddresses = ipProps.UnicastAddresses;
foreach (UnicastIPAddressInformation addressInfo in uniAddresses)
{
if (addressInfo.Address.IsIPv6LinkLocal)
{
firstLinkLocal = addressInfo.Address;
break;
}
}
if (firstLinkLocal != null)
{
break;
}
}
if (firstLinkLocal != null)
{
return firstLinkLocal.ScopeId;
}
else
{
return -1;
}
}

connect() - IP blocked, how to connect using hostname?

when I try to connect to a webserver, my "FritzBox" (residential gateway device) is configured to block all connections that connect directly to an IP, not a host name.
However, the connect() function only lets me connect using an IP address.
How can I connect() to a server using the host name (the way web browsers do)?
Many thanks.
... my "FritzBox" (residential gateway device) is configured to block all connections that connect directly to an IP, not a host name...
It looks like you are trying to bypass the settings of the child protection feature of the Fritzbox. What these settings mean in reality is that it will only allow HTTP connections which have a real hostname inside the Host-header of the HTTP-Request and not connections containing an IP only, i.e. it will allow http://example.com/ but not http://10.10.10.10/. For an example of the Host header look at the HTTP example request at Wikipedia.
First of all connections are always connecting to an IP address, not a host name. So your gateway is doing something else than what you're telling us, it can't tell the difference on how a client connects to something. What it could do is inspect certain protocols specifically, e.g. look for a Host: header in HTTP requests.
But to answer your question: You need to look up the host name with DNS and convert it to an IP address. This can be done all in one go by the getaddrinfo() function, getaddrinfo() will perform lookups in a platform specific way by e.g. looking at host files and/or do DNS lookups: e.g.
int clientfd;
struct addrinfo hints, *servinfo, *p;
int rc;
const char *port = "80";
const char *host = "www.google.com";
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((rc = getaddrinfo(host, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
exit(1);
}
// getaddrinfo() can map the name to several IP addresses
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((clientfd= socket(p->ai_family,
p->ai_socktype,p->ai_protocol)) == -1) {
perror("socket()");
continue;
}
if (connect(clientfd, p->ai_addr, p->ai_addrlen) == -1) {
close(sockfd);
continue;
}
break; //got a connection
}
if (p == NULL) {
fprintf(stderr, "connect() failed\n");
exit(2);
}
freeaddrinfo(servinfo);
//use clientfd

Destination Unreachable (Port Unreachable) using Haskell

Using Wireshark to debug, I receive the following error when sending UDP packets on localhost:
Destination Unreachable (Port Unreachable)
Checksum: 0x0000 (Illegal)
I am constructing my server first on a port between 10000 - 15000 using
startServer :: Port -> IO Server
startServer port = withSocketsDo $ do
-- Look up the server address and port information.
addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
let serverAddress = head addrs
-- Bind to the socket.
sock <- socket (addrFamily serverAddress) Datagram defaultProtocol
bindSocket sock (addrAddress serverAddress)
-- Create the server and run the client send and receive threads.
clients <- newMVar $ createEmptyClients
let server = Server sock port clients
_ <- forkIO $ forever $ receiveClientJoin server
return server
I am listening for new clients connecting via UDP using
-- | Connected a client to the server.
receiveClientJoin :: Server -> IO ()
receiveClientJoin server = do
print "Receiving"
(msg, _, clSockAddr) <- recvFrom (sSocket server) 4096
print $ "Server received client join message: " ++ msg
And I am connecting to the server with clients using
connectToServer port = do
-- Get the server's address and port information.
addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
let serverAddr = head addrInfo
sock <- socket (addrFamily serverAddr) Datagram defaultProtocol
sendTo sock "Hello from this client!" (addrAddress serverAddr)
Why are my clients' packets not finding the server?
The problem is you are listening on an IPv6 address and trying to connect to an IPv4 address. This is actually a slightly common problem. For example, I ran across this issue when working with commsec.
Consider the fragments where you discover your AddrInfo:
import Network.Socket
main :: IO ()
main = do
let port = "2474"
addrs <- getAddrInfo (Just $ defaultHints { addrFlags = [AI_PASSIVE] }) Nothing (Just port)
let serverAddress = head addrs
print serverAddress
addrInfo <- getAddrInfo Nothing (Just "localhost") (Just port)
let serverAddr = head addrInfo
print serverAddr
Now the output will vary by machine, but on one of my CentOS systems with both IPv4 and IPv6 addresses the output clearly shows the second (connect) address is IPv6 while the first (listen) address is IPv4:
AddrInfo {addrFlags = [AI_PASSIVE], addrFamily = AF_INET, addrSocketType = Stream, addrProtocol = 6, addrAddress = 0.0.0.0:2474, addrCanonName = Nothing}
AddrInfo {addrFlags = [AI_ADDRCONFIG,AI_V4MAPPED], addrFamily = AF_INET6, addrSocketType = Stream, addrProtocol = 6, addrAddress = [::1]:2474, addrCanonName = Nothing}
One solution is to force a particular version of IP via a hint or an address (ex. an IPv4 address as in my comment). The hint solution is probably more desirable:
-- For servers:
addrs <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6
, addrFlags = [AI_PASSIVE] })
Nothing (Just port)
-- For clients:
addrInfo <- getAddrInfo (Just defaultHints { addrFamily = AF_INET6 })
(Just "localhost") (Just port)

UDP send and receive between two programs in specific ports

I have a complete program that communicates via UDP protocol. Program runs on a PC with ip 192.168.1.9. When I send specific data, this program responds.
code for sending:
var client = new UdpClient();
IPEndPoint destination = new IPEndPoint(IPAddress.Parse("192.168.1.9"), 1531);
IPAddress localIp = IPAddress.Parse("192.168.1.3");
IPEndPoint source = new IPEndPoint(localIp, 1530);
client.Client.Bind(source);
client.Connect(destination);
byte[] send_buffer = { 170, 170, 0, 0, 1, 1, 86 };
client.Send(send_buffer, send_buffer.Length);
Wireshark captures:
Screen
But my application does not detect anything:
UdpClient listener = new UdpClient(1530);
IPAddress ip = IPAddress.Parse("192.168.1.3");
IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, 1530);
byte[] receive_byte_array;
while (!done)
{
Console.WriteLine("Waiting for broadcast");
receive_byte_array = listener.Receive(ref groupEP);
}
I need to capture communications from 192.168.9 to 192.168.1.3 on port 1530.
Your sender is binding to local IP 192.168.1.3 on port 1530 as its source, and then sending data to remote IP 192.168.1.9 on port 1531 as the destination.
Your receiver is binding to local IP 0.0.0.0 on port 1530 for receiving data, and then filtering out any inbound data that was NOT sent from remote port 1530 (which it is).
The data is not being sent to the port that the receiver is reading on.
To fix that, you need to either:
change your receiver to bind to port 1531 instead of port 1530:
UdpClient listener = new UdpClient(1531);
change your sender to send the data to port 1530 instead of port 1531:
IPEndPoint destination = new IPEndPoint(IPAddress.Parse("192.168.1.9"), 1530);

How to force client in UDP to open port when sending with sendto

I have simple server and client in UDP (WinSocks/C++).
I send datagram client -> server via sendto, and reply from server to client using the ip and port obtained from recvfrom function.
I found out that:
Every sendto from client is being sent from different port
When trying to reply from server Windows returns WSAECONNRESET (which mean that port is closed - http://support.microsoft.com/kb/263823)
How can I properly answer client from server (ie force port binding on client when sending using sendto?)
Edit: Adding some source code:
bool InitClient()
{
internal->sock = socket(PF_INET, SOCK_DGRAM, 0);
char8 yes = 1;
setsockopt(internal->sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int32));
return internal->sock != -1;
}
void Send(const IpAddress & target, const uint16 port, const char8 * data, int32 size )
{
sockaddr_in trgt;
memset(&trgt, 0, sizeof(trgt));
trgt.sin_family = AF_INET;
trgt.sin_port = htons(port);
trgt.sin_addr.s_addr = target.GetRaw();
if(sendto(internal->sock, (const char8 *)data, size, 0, (PSOCKADDR)&trgt, sizeof(trgt)) == SOCKET_ERROR)
{
LOG("Network sending error: %d", WSAGetLastError());
}
}
Call the "bind" function to specify a local port to send from. Example of using port 4567 below. Make sure to check the return value from bind.Call this code after you create the socket.
sockaddr_in local = {};
local.family = AF_INET;
local.port = htons(4567);
local.addr = INADDR_ANY;
bind(internal->sock,(sockaddr*)&local, sizeof(local));
If you bind to port zero instead of 4567 then the os will pick a random port for you and use it for all subsequent send and receives. You can call getsockname to discover which port the os picked for you after calling bind.