#include <iostream>
#include <cstdlib> // rand
// #include <winsock.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <elib/aliases.hpp>
using namespace elib::aliases;
#pragma pack( push, 1 )
namespace eth {
struct ipv4 {
// base
u8 ihl:4; // 32-bit blocks count of ip-head
u8 version:4; // must be 4
u8 tos; // type of service
u16 packsize; // total size of packet
// fragmentation
u16 fuid; // fragstream uid
u8 fzero:1; // must be zero
u8 fdisable:1; // disable fragmentation
u8 fmore:1; // current fragment is not last
u16 foffset:13; // fragment ordinal number
// advanced
u8 ttl; // time to live
u8 protocol; // next level of tcp/ip stack
u16 checksum; // head checksum
u32 source; // sender's ipv4-address
u32 destination; // receiver's ipv4-address
};
struct udp {
u16 sport;
u16 dport;
u16 length;
u16 checksum;
};
}; // namespace eth
template< u32 datasize >
struct udppacket {
eth::ipv4 iphead;
eth::udp udphead;
char data[datasize];
};
int main( int argc, char **argv )
{
WSADATA wsadata;
WSAStartup( 0x0202, &wsadata );
SOCKET s = socket( AF_INET, SOCK_RAW, IPPROTO_RAW );
if( s == INVALID_SOCKET ) {
std::cout << "error: invalid socket\n";
return -1;
};
BOOL optval = TRUE;
if( setsockopt(s,IPPROTO_IP,IP_HDRINCL,(char*)&optval,sizeof(optval))==SOCKET_ERROR ) {
std::cout << "error: failed to set socket in raw mode\n";
return -1;
};
udppacket<1024> packet;
// ip
packet.iphead.version = 4;
packet.iphead.ihl = 5;
packet.iphead.tos = 0;
packet.iphead.packsize = htons( sizeof(packet) );
packet.iphead.fuid = rand();
packet.iphead.fzero = 0;
packet.iphead.fdisable = 0;
packet.iphead.fmore = 0;
packet.iphead.foffset = 0;
packet.iphead.ttl = 32;
packet.iphead.protocol = 17; // udp
packet.iphead.checksum = 0;
packet.iphead.source = inet_addr("192.168.100.118");
packet.iphead.destination = inet_addr("192.168.100.254");
// udp
packet.udphead.sport = htons(65000);
packet.udphead.dport = htons(65000);
packet.udphead.length = htons( sizeof(packet.udphead) + sizeof(packet.data) );
packet.udphead.checksum = 0;
// data
memset( packet.data, 0, sizeof(packet.data) );
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = 0;
address.sin_addr.s_addr = inet_addr("192.168.100.254");
memset( address.sin_zero, 0, sizeof(address.sin_zero) );
std::cout << "sendto: " <<
sendto( s, (char*)&packet, sizeof(packet), 0, (SOCKADDR*)&address, sizeof(address) )
<< '\n';
WSACleanup();
std::cin.get();
return 0;
};
Raw сокеты, ручное формирование Ethernet-II фреймов
Есть ли возможность самостоятельного формирования ethernet-II фрейма ручками, без создания собственного драйвера (более-менее `штатными` средствами)?
Пока получается формировать стек, начиная с `ip`.
Как видно из кода и того, что мне даёт wireshark, фрейм формируется в процедуре sendto и ниже:
> `Destination-MAC` получается из ARP-таблицы по IP-адресу (в данном случае `IPv4`) указанному в структуре sockaddr (sockaddr_in);
> `Source-MAC` подставляется свой (с учетом маршрута, а следовательно и интерфейса);
> Поле `type` eth-фрейма вычисляется в соответствии с семейством (поле sin_family структуры sockaddr_in);
Хочется реализовать mac-спуффинг, не изменяя мак-адрес сетевой карточки. Т.е. слать с одной карточки фреймы с различными значениями `Source-MAC` (ну и при желании стальные два поля);
Отсюда вытекает еще вопрос: если необходимо вручную формировать все эти параметры, следовательно нужно явно указать интерфейс, через который произойдет отправка. Как?
Вот то, что я налабал:
Код:
Буду копать в сторону <неведомая сторона>. )
Честна, вроде как MS "обещались", что c RAW сокетами будет всё тяжелее и тяжелее, начиная с Vista (7), еще до её выхода, если исходить из этого, штатные средства если и есть, скоро их не будет...