I wrote a network ICMP ping code in C, the following is my code, it tried to ping thousands of IP, but after a few days run, the total number of open socket increased to 35K. Where should I release my socket please.
struct packet {
struct icmphdr hdr;
char msg[64 - sizeof(struct icmphdr)];
};
struct protoent *proto = NULL;
void ping(char *bindIp, char **ipArr, size_t ipCount) {
//bindIp is the Ip in my machine for sending ip
//ipArr is the destination Ips need to ping
//ipCount is the total destination ip number
const int val = 255;
int i, sd, cnt = 1;
struct sockaddr_in r_addr;
r_addr.sin_family = AF_INET;
r_addr.sin_addr.s_addr = inet_addr(bindIp);
r_addr.sin_port = 0;
sd = socket(PF_INET, SOCK_RAW, proto->p_proto);
bind(sd, (struct sockaddr *) &r_addr, sizeof(r_addr));
if (sd < 0) {
perror("socket,you might need root/admin to operate\n");
return;
}
if (setsockopt(sd, SOL_IP, IP_TTL, &val, sizeof(val)) != 0)
perror("Set TTL option");
if (fcntl(sd, F_SETFL, O_NONBLOCK) != 0)
perror("Request nonblocking I/O");
for (i = 0; i < ipCount; i++) {
struct packet pckt;
struct hostent *hname;
hname = gethostbyname(ipArr[i]);
struct sockaddr_in addr;
proto = getprotobyname("ICMP");
bzero(&addr, sizeof(addr));
addr.sin_port = 0;
addr.sin_family = hname->h_addrtype;
addr.sin_addr.s_addr = *(long*) hname->h_addr;
if(i%5==0){
usleep(1001);
if(i%50000==0){
printf("ping oversea--i=%d,ip=%s\n",i,ipArr[i]);
}
}
bzero(&pckt, sizeof(pckt));
pckt.hdr.type = ICMP_ECHO;
long currTs = current_timestamp();
char buffer[20];
sprintf(buffer,"_%lu", currTs);
char *payload=concat(sendIp,buffer);
strcpy(pckt.msg,payload);
pckt.hdr.un.echo.id = 8899;
pckt.hdr.un.echo.sequence = cnt++;
pckt.hdr.checksum = checksum(&pckt, sizeof(pckt));
free(payload);
sendto(sd, &pckt, sizeof(pckt), 0, (struct sockaddr*) &addr,
sizeof(addr));
}
}
You should close the socket at the end of the function. After the for loop.
Related
I'm trying to send a multicast message via a socket, then receive responses from devices on the network that respond.
The message sends successfully, and I can see the responses targeting the source IP address on wireshark, but attempting to call recvfrom just results in timeouts.
I have tried many combinations of socket options, bindings, but I've been unable to get past a timeout on recvfrom.
My current code (sending and receiving):
// Ethernet/IP Encapsulation Header
struct __attribute__((__packed__)) EnipEncapHeader
{
uint16_t command;
uint16_t length;
uint32_t session_handle;
uint32_t status;
uint64_t ctx_64;
uint32_t options;
};
int main() {
// initialize winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
// create a udp socket
int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0) {
printf("ERROR opening socket");
return 1;
}
// set the broadcast flag
int broadcastEnable = 1;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcastEnable, sizeof(broadcastEnable));
// Construct the message
struct EnipEncapHeader header;
header.command = 0x63;
header.length = 0x0000;
header.session_handle = 0x00000000;
header.status = 0x0000;
header.ctx_64 = (uint64_t)0;
header.options = 0x0000;
// send to 255.255.255.255 on port 44818
struct sockaddr_in servaddr;
memset(&servaddr, 0, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = inet_addr("255.255.255.255");
servaddr.sin_port = htons(44818);
// send the packet
int rc = sendto(sockfd, (const char*)&header, sizeof(header), 0, (struct sockaddr *)&servaddr, sizeof(servaddr));
if (rc < 0) {
printf("ERROR sending packet, %d, %d", rc, WSAGetLastError());
return 1;
}
// clear the broadcast flag
broadcastEnable = 0;
setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcastEnable, sizeof(broadcastEnable));
// set the timeout to 5 seconds
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (const char*)&tv, sizeof tv);
// bind the socket to any address
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port = htons(0);
bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr));
// recieve from any address on the socket
struct sockaddr_in from;
int fromlen = sizeof(from);
char buf[1024];
rc = recvfrom(sockfd, buf, sizeof(buf), 0, (struct sockaddr *)&from, &fromlen);
if (rc < 0) {
printf("ERROR recieving packet, %d, %d", rc, WSAGetLastError());
return 1;
}
else {
printf("Received %d bytes from %s:%d", rc, inet_ntoa(from.sin_addr), ntohs(from.sin_port));
}
return 0;
}
This code results in the following:
ERROR recieving packet, -1, 10060
Winsock Error 10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.
I have two programs: client and server. They're trying to find themselves in local network using broadcast.
Client sends simple packet on broadcast with SERVER_PORT (known before) and server prints info about connection, but when i tried this solution I found some strange behavaiour, when I uncomment last two lines of server.c server prints (one custom struct)
Connection from: 0.0.0.0 on port: 0
after commenting those lines everything works properly, am I missing something?
server.c
int broadcast_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
struct sockaddr_in broadcast_addr;
broadcast_addr.sin_addr.s_addr = INADDR_ANY;
broadcast_addr.sin_port = htons(SERVER_PORT);
broadcast_addr.sin_family = AF_INET;
if (bind(broadcast_socket, (struct sockaddr *)&broadcast_addr,
sizeof(broadcast_addr))) {
perror("bind");
}
struct sockaddr_in recv_addr;
char buf[MAX_PACKET_SIZE];
socklen_t len;
if (recvfrom(broadcast_socket, buf, MAX_PACKET_SIZE, 0,
(struct sockaddr *)&recv_addr, &len) < 0) {
perror("recvfrom");
}
printf("Connection from: %s on port: %d\nMessage: %s\n",
inet_ntoa(recv_addr.sin_addr), ntohs(recv_addr.sin_port), buf);
/* struct network_packet packet; */
/* struct sockaddr_in my_addr; */
client.c
int find_server(struct sockaddr_in *out) {
struct sockaddr_in broadcast;
struct network_packet packet;
int yes = 1;
socklen_t len;
broadcast.sin_addr.s_addr = INADDR_ANY;
broadcast.sin_port = htons(CLIENT_PORT);
broadcast.sin_family = AF_INET;
int socket_fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (bind(socket_fd, (struct sockaddr *)&broadcast, sizeof(broadcast))) {
perror("bind");
}
if (get_broadcast_addr(&broadcast.sin_addr)) {
return -1;
}
printf("Target address: %s\n", inet_ntoa(broadcast.sin_addr));
broadcast.sin_port = htons(SERVER_PORT);
broadcast.sin_family = AF_INET;
setsockopt(socket_fd, SOL_SOCKET, SO_BROADCAST, &yes, sizeof(yes));
char buf[10] = "test";
sendto(socket_fd, buf, strlen(buf), 0, (struct sockaddr *)&broadcast,
sizeof(broadcast));
if (recvfrom(socket_fd, &packet, sizeof(packet), 0,
(struct sockaddr *)&broadcast, &len) < 0) {
perror("recvfrom");
}
struct sockaddr_in *sa = (struct sockaddr_in *)packet.data;
memcpy(out, sa, packet.header.packet_length);
return 0;
}
struct network_packet_header {
enum network_packet_type type;
int packet_length;
};
struct network_packet {
struct network_packet_header header;
unsigned char data[MAX_DATA_LENGTH];
};
You have to initialize the variable you pass as recvfrom's addrlen to the size of the address struct.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
int create_socket(struct in_addr *ip, unsigned int port) {
int s = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = (port);
sin.sin_addr.s_addr = ip;
connect(s, &sin, sizeof(sin));
return s;
}
I try to create socket to connect to of my server, and whenever I run this code the process tries to connect to a random socket.
the function is called with the following parameters:
inet_aton(argv[1], &ip); //argv[1]=='127.0.0.1'
unsigned int port = htons(atoi(argv[2])); //argv[2]=='8080'
Anyone detects the mistake?
The problem was with this:
int create_socket(struct in_addr *ip, unsigned int port) {
int s = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = (port);
sin.sin_addr.s_addr =ip->s_addr; // this is where the problem was
err_handler(connect(s, (struct sockaddr *)&sin, sizeof(sin)));
return s;
}
Try something more like this:
int create_socket(struct in_addr *ip, unsigned short port) {
int s = socket(AF_INET, SOCK_STREAM, 0);
if (s < 0) return -1;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_port = htons(port);
sin.sin_addr.s_addr = ip->s_addr;
if (connect(s, &sin, sizeof(sin)) < 0) {
close(s);
s = -1;
}
return s;
}
struct in_addr ip;
inet_aton(argv[1], &ip); //argv[1]=="127.0.0.1"
unsigned short port = atoi(argv[2]); //argv[2]=="8080"
int sckt = create_socket(&ip, port);
if (sckt < 0) {
...
}
else {
...
close(sckt);
}
A better option is to use getaddrinfo() instead, let it do all the parsing and setup of the sockaddr_in for you:
int create_socket(const char *ip, const char *port) {
struct addrinfo hints, *addrs, *addr;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
int res = getaddrinfo(ip, port, &hints, &addrs);
if (res < 0) {
return -1;
}
for(addr = addrs; addr != NULL; addr = addr->ai_next) {
int s = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (s < 0) continue;
if (connect(s, addr->ai_addr, addr->ai_addrlen) == 0) {
freeaddrinfo(addrs);
return s;
}
close(s);
}
freeaddrinfo(addrs);
return -1;
}
int sckt = create_socket(argv[1], argv[2]);
if (sckt < 0) {
...
}
else {
...
close(sckt);
}
a demo about UDP multicast,when i want to test if the code is right, I found failed ,but i think is not the problem of the code.My virtual machine is offline,so i think whether is udp cannot multicast when the machine is offline?
this is my code:
//this is for receive
int main(int argc,char **argv) //My Multicast address is 224.0.0.88
{
int udpsocket;
int res;
char buf[50];
struct sockaddr_in saddr;
struct sockaddr_in raddr;
bzero(&saddr,sizeof(saddr));
bzero(&raddr,sizeof(raddr));
// 初始化地址结构体变量
saddr.sin_family = AF_INET;
saddr.sin_port = htons(5001);
saddr.sin_addr.s_addr = htonl(INADDR_ANY);
// 定义并初始化组播的结构体
struct ip_mreq mreq;
bzero(&mreq, sizeof mreq);
mreq.imr_multiaddr.s_addr = inet_addr(argv[1]); //组播地址,D类型
mreq.imr_interface.s_addr = htonl(INADDR_ANY);
// 创建udp套接字
udpsocket = socket(AF_INET,SOCK_DGRAM,0);
if(udpsocket == -1)
{
perror("create udp socket failed!\n");
return -1;
}
// 设置可以组播
setsockopt(udpsocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,
&mreq, sizeof mreq);
int ret = sizeof(struct sockaddr);
// 绑定
res = bind(udpsocket,(struct sockaddr *)&saddr,ret);
if(res == -1)
{
perror("bind udp socket failed!\n");
return -1;
}
while(1)
{
puts("111");
bzero(buf,50);
recvfrom(udpsocket,buf,50,0,(struct sockaddr *)&raddr,&ret);
printf("message recv from %s\n",buf);
}
close(udpsocket);
return 0;
}
//this is for send message
int main(int argc,char **argv)
{
int udpsocket;
int res;
char buf[50];
struct sockaddr_in saddr;
bzero(&saddr,sizeof(saddr));
// 初始化地址结构体变量
saddr.sin_family = AF_INET;
saddr.sin_port = htons(5001);
saddr.sin_addr.s_addr = inet_addr(argv[1]);
// 创建udp套接字
udpsocket = socket(AF_INET,SOCK_DGRAM,0);
if(udpsocket == -1)
{
perror("create udp socket failed!\n");
return -1;
}
// 将套接字的属性设置为可以广播
int on = 1;
setsockopt(udpsocket, SOL_SOCKET, SO_BROADCAST, &on, sizeof on);
setsockopt(udpsocket,SOL_SOCKET,SO_REUSEADDR,&on,sizeof on);
int ret = sizeof(struct sockaddr);
while(1)
{
bzero(buf,50);
printf("please input a message !\n");
scanf("%s",buf);
sendto(udpsocket,buf,50,0,(struct sockaddr *)&saddr,ret);
}
close(udpsocket);
return 0;
}
So, I have the raw sockets set up with some copypasta, it sends data, that part is working fine. But how would I set the data send over the socket? I'm looking to make a DNS request, if that helps. Code below.
int main(int argc, char *argv[])
{
if (!argv[1])
{
printf("Target not specified!\nUsage: ");
printf(argv[0]);
printf(" <target>\n");
exit(1);
}
struct ip ip;
struct udphdr udp;
int sd;
const int on = 1;
struct sockaddr_in sin;
//char msg[] = "\x03\xF0\x01\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x01";
u_char *packet;
packet = (u_char *)malloc(120);
ip.ip_hl = 0x5;
ip.ip_v = 0x4;
ip.ip_tos = 0x0;
ip.ip_len = 60;
ip.ip_id = htons(12830);
ip.ip_off = 0x0;
ip.ip_ttl = 64;
ip.ip_p = IPPROTO_UDP;
ip.ip_sum = 0x0;
ip.ip_src.s_addr = inet_addr(argv[1]);
ip.ip_dst.s_addr = inet_addr("67.228.44.4");
ip.ip_sum = in_cksum((unsigned short *)&ip, sizeof(ip));
memcpy(packet, &ip, sizeof(ip));
udp.source = htons(80);
udp.dest = htons(53);
udp.len = htons(22);
udp.check = 0;
udp.check = in_cksum_udp(ip.ip_src.s_addr, ip.ip_dst.s_addr, (unsigned short *)&udp, sizeof(udp));
memcpy(packet + 20, &udp, sizeof(udp));
if ((sd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("raw socket");
exit(1);
}
if (setsockopt(sd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) {
perror("setsockopt");
exit(1);
}
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ip.ip_dst.s_addr;
if (sendto(sd, packet, 120, 0, (struct sockaddr *)&sin, sizeof(struct sockaddr)) < 0)
{
perror("sendto");
exit(1);
}
}
Hmmm...I think you're wondering how to set the payload in your message? Basically, you want to offset from the IP and UDP headers and start writing your payload data at that point.
A hastily thrown together example of this:
int offset = packet + sizeof(struct ip) + sizeof(struct udphdr);
Then you can write your payload as follows:
strcpy(offset, "1234");
Here's some working ICMP code that is effectively writing out the data over a RAW IP socket:
struct icmphdr *icmp_hdr;
char *datapart;
icmp_hdr = (struct icmphdr *) icmp_data;
icmp_hdr->i_type = ICMP_ECHO;
icmp_hdr->i_code = 0;
icmp_hdr->i_id = (unsigned short) getpid();
icmp_hdr->i_cksum = 0;
icmp_hdr->i_seq = 0;
datapart = icmp_data + sizeof(struct icmphdr);
memset(datapart, 'E', datasize - sizeof(struct icmphdr));