从C scoket从发送UDP路由器和处理ICMP回复 [英] C sockets send UDP and process ICMP reply from router

查看:330
本文介绍了从C scoket从发送UDP路由器和处理ICMP回复的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想一个UDP数据包发送到与生存时间的1路由器,然后到接收ICMP超时答复。到目前为止,我能够发送数据包,但是当我的程序获取到执行的recv的一部分,它只是挂起。我有recvfrom的错误检查,但它不连到这一点。我的电脑正在接收请求。我知道这是因为我跑Wireshark的,当我运行该程序,我过滤掉ICMP请求。我每次运行程序时,我收到了回复。什么是我与recvfrom的做错了吗?

 的#include<&stdio.h中GT;
#包括LT&;&string.h中GT;
#包括LT&; SYS / types.h中>
#包括LT&; SYS / socket.h中>
#包括LT&;&netdb.h中GT;
#包括LT&; ARPA / inet.h>
#包括LT&; netinet / in.h中>
#包括LT&;&errno.h中GT;#定义UNSPEC_PROTO 0INT主(INT ARGC,为const char * argv的[])
{
如果(的argc!= 2){
    输出(用法:routetracer< IP地址或主机名> \\ n);
    返回-1;
}结构addrinfo中的提示; //为PARAMS中的getaddrinfo RET VAL
结构addrinfo中的* RET; //的getaddrinfo的返回值
结构sockaddr * REPLY_ADDR;
焦炭的IPv4 [INET_ADDRSTRLEN]
字符*味精=端口超过9000 !!!!;
INT状态= 0;
INT TTL = 0;
INT src_sock = 0;
INT recv_sock = 0;
socklen_t的reply_addr_len = sizeof的(结构sockaddr);
为const char * dest_port =9001;
INT icmp_msg_len = 100;
烧焦icmp_msg [icmp_msg_len]//定义我们从希望的getaddrinfo
memset的(安培;提示,0,sizeof的(提示));
hints.ai_family = AF_INET; //的IPv4
hints.ai_socktype = SOCK_DGRAM; // UDP数据包//调用的getaddrinfo填补RET,W /错误CHK
如果((状态=的getaddrinfo(的argv [1],dest_port,&放大器;提示,&放大器;!保留))= 0){
    的printf(的getaddrinfo:%S \\ n,gai_strerror(状态));
    返回-1;
}//提取RET IPv4地址
结构SOCKADDR_IN * IP =(结构SOCKADDR_IN *)ret-> ai_addr;//从单纯的数字转换地址的东西更容易阅读
inet_ntop(ret-> ai_family,及(IP-> sin_addr),IPv4的,INET_ADDRSTRLEN);//可否告知他们连接到主机的用户
的printf(路线为:%S \\ n,IPv4)的;//创建我们的机器插座
如果((src_sock =插座(ret-> ai_family,ret-> ai_socktype,
                ret-> ai_protocol))≤; 0){
    fprintf中(标准错误,错误创建主机插座:%S \\ n字符串错误(错误));
    返回-1;
}//创建一个插座的recv从啤酒花icmp包
如果((recv_sock =插座(AF_INET,SOCK_DGRAM,UNSPEC_PROTO))小于0){
    fprintf中(标准错误,错误创建的recv套接字:%S \\ n字符串错误(错误));
}/ *
 *我们从跳去通过增加时间住在IP报头跳
 *对于每一跳我们访问,直到我们达到目的IP地址(我们
 * 已经有)。存活时间递减,每经过一跳,所以一旦它到达
 *零我们报告,我们连接到节点的IP地址。
 * ///而(test_ip!= DEST_IP)
// time_to_live ++
// send_to(dest_addr)
//收到的ICMP错误信息
//从ICMP的IP报头得到错误味精源地址
// test_ip =源地址
/ *
而(last_hop == 0){
    TTL ++;
    setsockopt的(袜子,IPPROTO_IP,IP_TTL,&安培; TTL,sizeof的(TTL));
    SENDTO(袜子,味精,strlen的(MSG),0,(结构sockaddr *)IP,的sizeof(IP));
}
* /TTL = 1;
如果((setsockopt的(src_sock,IPPROTO_IP,IP_TTL,&安培;!TTL,sizeof的(TTL)))){
    的printf(TTL设置成功的\\ n);
}其他{
    的printf(错误设置TTL:%S \\ n字符串错误(错误));
}如果((SENDTO(src_sock,味精,strlen的(MSG),0,ret-> ai_addr,
                ret-> ai_addrlen))GT; 0){
    的printf(味精已成功发送的\\ n);
}其他{
    fprintf中(标准错误,发送错误信息:%S \\ n字符串错误(错误));
}如果((recvfrom的(recv_sock,icmp_msg,icmp_msg_len,0,REPLY_ADDR,
                &放大器;!reply_addr_len))= -1){
    / *过程中的信息* /
    的printf(数据包接收\\ n);
}其他{
    fprintf中(标准错误,错误报文接收%S \\ n字符串错误(错误));
}返回0;
}


解决方案

通常情况下,UDP pretty多少忽略ICMP错误,所以如果你想看到他们,你需要打开一个原始套接字接收的所有的ICMP数据包,并查找有关您的插座的。

在Linux上,至少,另一种方法是将 IP_RECVERR 套接字选项。如果你这样做,你可以做一个 recvmsg MSG_ERRQUEUE 标志设置为得到任何ICMP(或其它)错误与套接字关联。这有不需要提升权限或第二插座的优势。

I'm trying to send a UDP packet to a router with a time to live of 1, to then receive an ICMP time exceeded reply. So far I'm able to send the packet, but when my program gets to the recv part of the execution, it just hangs. I have an error check for recvfrom, but it doesn't even get to that. My computer is receiving the request. I know this because I run Wireshark when I run the program and I filter for ICMP requests. Every time I run the program, I receive the reply. What am I doing wrong with recvfrom?

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>

#define UNSPEC_PROTO 0

int main(int argc, const char *argv[])
{ 
if (argc != 2) {
    printf("usage: routetracer <ip address or hostname>\n");
    return -1;
}

struct addrinfo hints; //params for ret val of getaddrinfo
struct addrinfo* ret; //return value of getaddrinfo
struct sockaddr* reply_addr;
char ipv4[INET_ADDRSTRLEN];
char* msg = "THE PORT IS OVER 9000!!!!";
int status = 0;
int ttl = 0;
int src_sock = 0;
int recv_sock = 0;
socklen_t reply_addr_len = sizeof(struct sockaddr);
const char* dest_port = "9001";
int icmp_msg_len = 100;
char icmp_msg[icmp_msg_len];

//define what we want from getaddrinfo
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; //IPv4
hints.ai_socktype = SOCK_DGRAM; //UDP packets

//call getaddrinfo to fill ret, w/ error chk
if ((status = getaddrinfo(argv[1], dest_port, &hints, &ret)) != 0) {
    printf("getaddrinfo: %s\n", gai_strerror(status));
    return -1;
}

//extract IPv4 address from ret
struct sockaddr_in* ip = (struct sockaddr_in *)ret->ai_addr;

//convert address from pure numbers to something easier to read
inet_ntop(ret->ai_family, &(ip->sin_addr), ipv4, INET_ADDRSTRLEN);

//kindly inform the user of which hostname they are connecting to
printf("Route for: %s\n", ipv4);

//create a socket for our machine
if ((src_sock = socket(ret->ai_family, ret->ai_socktype, 
                ret->ai_protocol)) < 0) {
    fprintf(stderr, "Error creating host socket: %s\n", strerror(errno));
    return -1;
}

//create a socket to recv icmp packet from hops 
if ((recv_sock = socket(AF_INET, SOCK_DGRAM, UNSPEC_PROTO)) < 0){
    fprintf(stderr, "Error creating recv socket: %s\n", strerror(errno));
}

/*
 * We go from hop to hop by incrementing the time to live in the IP header
 * for each hop we visit until we reach the destination IP address (which we
 * already have). Time to live decrements for every hop, so once it reaches
 * zero we report the IP address of the node we are connected to.
 */

//while(test_ip != dest_ip)
//time_to_live++
//send_to(dest_addr)
//receive icmp error message
//get src addr of error msg from ip header of icmp
//test_ip = src addr
/*
while (last_hop == 0) {
    ttl++;
    setsockopt(sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl));
    sendto(sock, msg, strlen(msg), 0, (struct sockaddr *)ip, sizeof(ip));
}
*/

ttl = 1;
if (!(setsockopt(src_sock, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)))) {
    printf("TTL set successfully\n");
} else {
    printf("Error setting TTL: %s\n", strerror(errno));
}

if ((sendto(src_sock, msg, strlen(msg), 0, ret->ai_addr, 
                ret->ai_addrlen)) > 0) {
    printf("msg sent successfully\n");
} else {
    fprintf(stderr, "Error sending msg: %s\n", strerror(errno));
}

if ((recvfrom(recv_sock, icmp_msg, icmp_msg_len, 0, reply_addr, 
                &reply_addr_len)) != -1) {
    /* PROCESS THE INFORMATION */
    printf("Packet received\n");
} else {
    fprintf(stderr, "Error receiving packet: %s\n", strerror(errno));
}

return 0;
}

解决方案

Normally, UDP pretty much ignores ICMP errors, so if you want to see them, you need to open a raw socket to receive all ICMP packets and look for ones relevant to your socket.

On Linux, at least, an alternative is to set the IP_RECVERR socket option. If you do that, you can do a recvmsg with the MSG_ERRQUEUE flag set to get any ICMP (or other) errors associated with your socket. This has the advantage of not requiring elevated privileges or a second socket.

这篇关于从C scoket从发送UDP路由器和处理ICMP回复的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆