Установка setsockopt для обнаружения IP-опции
Я хочу, чтобы обнаружить IP-параметры входящих интернет-пакетов. Вот мой код
//#define IPPROTO_IP 0
//#define IP_OPTIONS 68
#define SENDER_PORT_NUM 53
#define SENDER_IP_ADDR "127.0.0.1"
#define true 1
static void bail(const char *error)
{
printf("%s: %s\n", error, strerror(errno));
exit(1);
}
struct ip_datagram{
unsigned char ver_ihl;
unsigned char tos;
unsigned short totlen;
unsigned short id;
unsigned short flags_offs;
unsigned char ttl;
unsigned char proto;
unsigned short checksum;
unsigned long src;
unsigned long dst;
unsigned char payload[1500];
};
int main(){
int s,b,sso,gso, i;
int contatore = 5;
int enabled = 1;
char *data, *buffer;
int addrlen;
struct sockaddr_in addr;
struct ip_datagram *ip, *ip_reply;
struct icmphdr* icmp;
//char *src_addr="93.34.229.111";
char *dst_addr="127.0.0.1";
data = malloc(sizeof(struct ip_datagram)+ sizeof(struct icmphdr));
buffer = malloc(sizeof(struct ip_datagram)+ sizeof(struct icmphdr));
ip = (struct ip_datagram *) (data );
icmp = (struct icmphdr*) (data + sizeof(struct ip_datagram));
ip->ver_ihl = 45;
//ip->ihl = 15;
ip->totlen = sizeof(struct ip_datagram);
ip->proto = IPPROTO_ICMP;
//ip->src =(inet_addr(src_addr));
ip->dst = inet_addr(dst_addr);
ip->checksum = in_cksum((unsigned short *)ip, sizeof(struct ip_datagram));
icmp->type = ICMP_ECHO;
icmp->checksum = in_cksum((unsigned short *)icmp, sizeof(struct icmphdr));
s = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
if(s<0)
printf("errore socket\n");
sso = setsockopt(s, IPPROTO_IP, IP_OPTIONS, &enabled, sizeof(enabled));
if(sso<0)
bail("errore setsockoptions\n");
gso = (s, IPPROTO_IP, IP_OPTIONS, &enabled, sizeof(enabled));
if(gso<0)
bail("errore getsockoptions\n");
else
printf("IP_OPTIONS VALUE :%d\n", enabled);
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ip->dst;
while(contatore>0){
int sent_bytes = sendto(s, (const char *)data, ip->totlen, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr) );
if(sent_bytes <0){
printf("failed to send packets\n");
return 3;
}
//printf("Sent %d byte packet from %s to %s\n", ip->totlen, src_addr, dst_addr);
printf("Sent %d byte packet to %s\n", ip->totlen, dst_addr);
addrlen = sizeof(addr);
int bytes = recvfrom(s, buffer, sizeof(struct ip_datagram) + sizeof(struct icmphdr), 0, (struct sockaddr*)&addr, &addrlen);
if(bytes<=0){
printf("errore recvfrom\n");
break;
}
else{
char *cp;
ip_reply = (struct ip_datagram*) buffer;
cp = (char *)&ip_reply->src;
printf("Received %d byte reply from %u.%u.%u.%u:\n", ntohs(ip_reply->totlen), cp[0]&0xff,cp[1]&0xff,cp[2]&0xff,cp[3]&0xff);
printf("ID: %d\n", ntohs(ip_reply->id));
printf("TTL: %d\n", ip_reply->ttl);
printf("type of service: %.1X\n", ip_reply->tos);
printf("IP ADDRESS SOURCE: %.4X\n", htonl(ip_reply->src));
printf("IP ADDRESS DESTINATION: %.4X\n", htonl(ip_reply->dst));
printf("versione + header length: %.1X\n", ip_reply->ver_ihl);
contatore--;
printf("-----------------\n");
printf("****************\n");
}
}
}
проблема в том, что длина заголовка равна 6, но длина должна быть 20 для обнаружения всех параметров ip. В setsockopt, возможно, тип включенной переменной должен быть символом, но у меня есть некоторая проблема, когда я запускаю программу: фактически, с типом символа это дает мне ошибку для неверного аргумента. Я хочу знать также, как распечатать эти параметры, используя getsockoption. В чем проблема? я надеюсь, что мой вопрос ясен:)
1 ответ
Структура, которую вы определяете для своего IP-заголовка, МОЖЕТ быть в целом совместимой с заголовком IP-пакета, но на самом деле она недостаточно хороша и ее нелегко использовать.
В моей системе Linux системные заголовки определяют заголовок IP в /usr/include/linux/ip.h следующим образом:
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
__u8 ihl:4,
version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
__u8 version:4,
ihl:4;
#else
#error "Please fix <asm/byteorder.h>"
#endif
__u8 tos;
__be16 tot_len;
__be16 id;
__be16 frag_off;
__u8 ttl;
__u8 protocol;
__sum16 check;
__be32 saddr;
__be32 daddr;
/*The options start here. */
};
Как вы можете видеть, это правильно разделяет версию IP и длину заголовка, и безопаснее быть скомпилированным для больших или маленьких порядковых целей.
С таким определением структуры вы можете найти начало вариантов IP после sizeof(struct iphdr)
байт, а размер всего заголовка IP будет ip.ihl * 4
где ip является struct iphdr
,
Вам нужно умножение на 4 выше, потому что ihl
это число 32-битных слов, составляющих заголовок IP, а не количество байтов самого заголовка.
Вы можете посмотреть на IPv4 (Википедия), в котором содержится некоторая общая информация о параметрах заголовка IP и их формате, а также список параметров IP IPAN для полного списка со ссылками на различные RFC, которые описывают детали каждого параметра.