Packet sniffer for link layer protocols - linux

I am trying to convert a program called Responder which is written in Python to a C version. One of the spots I am stuck on is the listeners that listen on different ports. Responder listens for SMB on port 445 and 139. I created a small snippet that will listen on those ports as well. But when I run my program, I get no data.
void sniff(int PORT) {
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
if ((server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == 0) {
return;
}
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
return;
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
return;
}
if (listen(server_fd, 3) < 0) {
return;
}
printf("listen done.\n");
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
return;
}
valread = read( server_fd , buffer, 1024);
printf("%s\n",buffer );
return;
}
If I do the above, I don't get anything.

Related

getsockopt doesn't return error when trying to connect to a closed port

I try to use connect() & O_NONBLOCK to connect to a port in localhost asynchronously. In order to get the connect result, I use getsockopt to check the socket error status. I can sure no one listen to this port, so ECONNREFUSED should be returned. But in my test, this error may not be returned in some cases.
My test program:
int main() {
uint64_t p = 0;
while (1) {
int fd = ::socket(PF_INET, SOCK_STREAM, 0);
assert(fd > 0);
int flags = ::fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
int ret = ::fcntl(fd, F_SETFL, flags);
assert(ret != -1);
sockaddr_in addr;
bzero(&addr, sizeof(sockaddr_in));
addr.sin_family = AF_INET;
addr.sin_port = htons(25400);
addr.sin_addr.s_addr = inet_addr("127.0.0.1");
ret = ::connect(fd, (sockaddr *)&addr, sizeof(sockaddr));
assert(ret != 0);
switch (errno) {
case EINPROGRESS:
case EINTR:
case EISCONN:
break;
default:
assert(false);
}
int epfd = epoll_create1(0);
assert(epfd > 0);
epoll_event ev;
ev.events = EPOLLOUT;
ev.data.fd = fd;
ret = epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);
assert(ret == 0);
epoll_event events;
auto nfds = epoll_wait(epfd, &events, 1, -1);
assert(nfds == 1);
assert(events.data.fd == fd);
int err;
socklen_t optlen = static_cast<socklen_t>(sizeof err);
ret = ::getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &optlen);
assert(ret == 0);
assert(err != 0);
::close(fd);
::close(epfd);
if (p++ % 10000 == 0) {
std::cout << p << std::endl;
}
}
}
assert(err != 0); will be triggered.
In this test code, I use connect() without bind(), in this case, the source port is choosen by kernel. So the source port may be the same as destination port 25400. Due to the destination ip address is localhost, this TCP connection can be established in this case.

Linux to Windows PC Communication through Socket

I have used the linux part of code in windows to establish RDB communication. Though the socket opening is successful, I am unable to bind the socket with the IP Address defined. Is there any limitation between Linux and Windows over socket?
Here's my code,
SOCKET sock;
SOCKET sClient;
struct sockaddr_in server;
char szServer128; // Server to connect to
char szBuffer204800; // allocate on heap
sClient = udpsock_open(&server, szServer, DEFAULT_RX_PORT);
int udpsock_open(struct sockaddr_in *psa, char *ipv4, uint16_t port) {
WSADATA wsaData;
int opt;
int domain = AF_INET;
int type = SOCK_DGRAM;
int proto = IPPROTO_UDP;
sClient = WSAStartup(MAKEWORD(2, 2), &wsaData);
if (sClient 0)
printf(" WSAStartup Successful %I64d\n", sClient);
else
printf("Failed. Error Code : %d\n", WSAGetLastError());
// Prepare a socket to listen for connections
if ((sock = WSASocket(domain, type, 0, NULL, 0, WSA_FLAG_OVERLAPPED)) INVALID_SOCKET)
{
printf("WSASocket() failed with error %d\n", WSAGetLastError());
return 1;
}
else
{
printf("WSASocket() is OK!\n");
}
if (sock < 0)
{
//rtos_log ( LOG_ERR, "Failed to open socket %m" );
printf("Failed to open socket %I64d\n", sock);
return -1;
}
set_reuse(sock);
memset(psa, 0x00, sizeof(struct sockaddr_in));
psa->sin_family = domain;
psa->sin_port = htons(port);
psa->sin_addr.s_addr = inet_addr(ipv4);
if (bind(sock, ( struct sockaddr *)psa, sizeof(struct sockaddr_in)) < 0)
{
printf("Failed to bind socket Error: %d\n", WSAGetLastError());
closesocket(sock);
WSACleanup();
return -4;
}
opt = 1;
char buf[2048];
DWORD dwBytesRet;
//ioctlsocket(sock, FIONBIO, &opt)
if (WSAIoctl(sock, SIO_ADDRESS_LIST_QUERY,NULL,0, buf,2048, &dwBytesRet,NULL,NULL) == SOCKET_ERROR)
{
printf("ioctlsocket() failed with error %d\n", WSAGetLastError());
return 1;
}
else
{
printf("ioctlsocket() is OK!\n");
}
return sock;
}

Does libevent support netlink socket

I use netlink to receive an interrupt number from kernel. The application in user space uses libevent to handle TCP/IP request and netlink message. Does libevent support Linux netlink socket? I will appreciate for a simple example.
Yes, libevent supports netlink socket.
There is https://github.com/libevent/libevent/blob/master/sample/hello-world.c, it is modified below to listen to netlink socket.
The basic example listens to Linux network interface creation/deletion and can be executed with sudo to gain privilege needed. It listens to same events as ip monitor link.
Another example of listening to RAW sockets with libevent is here https://github.com/bodgit/libevent-natpmp/blob/master/natpmp.c.
static void link_recvmsg(int fd, short event, void *arg)
{
char buf[NLMSG_SPACE(BUF_SIZE)] = {0};
socklen_t socklen;
struct iovec iov = {.iov_base = buf, .iov_len = sizeof(buf)};
struct sockaddr addr;
memset(&addr, 0, sizeof(struct sockaddr));
if (!fd || -1 == fd)
return;
int status = getsockname(fd, &addr, &socklen);
if(-1 == status)
return;
struct msghdr mh = {.msg_name = NULL, .msg_namelen = 0, .msg_iov = &iov, .msg_iovlen = 1,
.msg_flags = 0, .msg_name = &addr, .msg_namelen = sizeof(struct sockaddr)};
status = recvmsg(fd, &mh, 0);
if ((-1 == status) && ((EINTR == errno) || (EAGAIN == errno)))
return;
if(-1 == status)
return;
if ((mh.msg_flags & MSG_TRUNC) == MSG_TRUNC)
return;
if ((mh.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
return;
for (const struct nlmsghdr *h = (struct nlmsghdr *)buf; NLMSG_OK(h, status); h = NLMSG_NEXT(h, status)) {
switch (h->nlmsg_type) {
case RTM_NEWLINK:
fprintf(stderr, "got RTM_NEWLINK\n");
break;
case RTM_DELLINK:
fprintf(stderr, "got RTM_DELLINK\n");
break;
default:
fprintf(stderr, "unexpected case in swtch statement\n");
break;
}
}
}
int main(int argc, char **argv)
{
/* some init code here */
/* NETLINK socket */
int status;
int buf_size = BUF_SIZE;
struct sockaddr_nl src_addr;
int socket_nl = socket(AF_NETLINK, SOCK_RAW | SOCK_NONBLOCK, NETLINK_ROUTE);
if(-1 == socket_nl) return -1;
memset(&src_addr, 0, sizeof(struct sockaddr_nl));
src_addr.nl_family = AF_NETLINK;
src_addr.nl_pid = getpid();
src_addr.nl_groups |= RTNLGRP_LINK;
status = setsockopt(socket_nl, SOL_SOCKET, SO_RCVBUF,
&buf_size, sizeof(buf_size));
if(-1 == status) return -1;
status = bind(socket_nl, (struct sockaddr *)&src_addr, sizeof(struct sockaddr_nl));
if(status < 0) return -1;
static struct event nl_ev;
event_set(&nl_ev, socket_nl, EV_READ|EV_PERSIST, link_recvmsg,
NULL);
if (base) {
event_base_set(base, &nl_ev);
}
event_add(&nl_ev, NULL);
/* some other code, dispatch event and deinit */
}

bind() picks zero port

I am trying to write some socket app and got a problem. I want OS to pick random free port number for my address.
But I receive port number = 0. What am I doing wrong?
struct sockaddr_in addr;
socklen_t addrLen;
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1) {
ThreadError("Failed to create data channel socket");
}
addr.sin_family = AF_INET;
addr.sin_port = 0; // pick random free port
addr.sin_addr.s_addr = srvAddr; // = inet_addr(127.0.0.1)
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) == -1) {
ThreadError("Failed to bind data channel");
}
if (getsockname(fd, (struct sockaddr *)&addr, &addrLen) == -1) {
ThreadError("getsockname() failed");
}
if (listen(fd, 1) == -1) {
ThreadError("Failed to set socket to listen mode");
}
// addr.sin_port == 0
You need to set addrlen = sizeof addr before you call getsockname.
The size is an in-out parameter. You specify the size of the buffer you're providing, and the function tells you how much of the buffer it used by modifying the size.

accept/epoll problem

I have this code that uses epoll and it has a problem. When I run it, it gives output:
Server-socket() is OK...
Server-bind() is OK...
3
4
accept: Invalid argument
I'm running it on ubuntu linux, system updated, both as limited user and root
what is wrong with the input to accept? What should I change?
struct epoll_event ev, events[MAX_EVENTS];
struct sockaddr_in serveraddr;
int listen_sock, conn_sock, nfds, epollfd;
int yes = 1;
/* Set up listening socket, 'listen_sock' (socket(),
bind(), listen()) */
if((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror("Server-socket() error lol!");
//just exit lol!
exit(1);
}
printf("Server-socket() is OK...\n");
//"address already in use" error message
/*if(setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
perror("Server-setsockopt() error lol!");
exit(1);
}
printf("Server-setsockopt() is OK...\n");*/
// bind
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = INADDR_ANY;
serveraddr.sin_port = htons(PORT);
memset(&(serveraddr.sin_zero), '\0', 8);
if(bind(listen_sock, (struct sockaddr *)&serveraddr, sizeof(serveraddr)) == -1)
{
perror("Server-bind() error lol!");
exit(1);
}
printf("Server-bind() is OK...\n");
epollfd = epoll_create(MAX_EVENTS);
if (epollfd == -1) {
perror("epoll_create");
exit(EXIT_FAILURE);
}
ev.events = EPOLLIN;
ev.data.fd = listen_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {
perror("epoll_ctl: listen_sock");
exit(EXIT_FAILURE);
}
for (;;) {
nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);
if (nfds == -1) {
perror("epoll_pwait");
exit(EXIT_FAILURE);
}
for (int n = 0; n < nfds; ++n) {
if (events[n].data.fd == listen_sock) {
struct sockaddr_in clientaddr;
socklen_t addrlen = sizeof(clientaddr);
cout <<listen_sock <<'\n' <<epollfd <<'\n';
conn_sock = accept(listen_sock, (struct sockaddr *) &clientaddr, &addrlen);
if (conn_sock == -1) {
perror("accept");
exit(EXIT_FAILURE);
}
fcntl(conn_sock, F_SETFL, fcntl(conn_sock, F_GETFD, 0)|O_NONBLOCK);
ev.events = EPOLLIN | EPOLLET;
ev.data.fd = conn_sock;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,
&ev) == -1) {
perror("epoll_ctl: conn_sock");
exit(EXIT_FAILURE);
}
} else {
printf("%d\n", events[n].data.fd);
}
}
}
You forgot to call listen() after bind():
listen(listen_sock, 5);
I built your source and had the same results. The epoll_wait returns immediately even though there is nothing to accept.
It appears to be the case that using epoll_wait instead of listen is not supported behavior.

Resources