Приступил к изучению raw-сокетов и запутался. В одних примерах рекомендуют создавать сырой сокет так:int s;
s = socket(AF_INET, SOCK_RAW, <protocol>);в других так:
int s;
s = socket(PF_PACKET, SOCK_RAW, <protocol>);У Стивенса, например, нет упоминания про семейство PF_PACKET. Подскажите чайнику - а как же правильнее?
Спасибо.
забыл добавить что экспериментирую на линуксе, ядро 2.4.20
up
man socket
int socket(int domain, int type, int protocol);
domain parameter:
PF_INET IPv4 Internet protocols ip(7)
PF_PACKET Low level packet interface packet(7)man packet
packet_socket = socket(PF_PACKET, int socket_type, int protocol);
Packet sockets are used to receive or send raw packets at the device driver (OSI Layer 2) level.man ip
raw_socket = socket(PF_INET, SOCK_RAW, protocol);
SOCK_RAW to open a raw(7) socket to access the IP protocol directly. protocol is the IP protocol in the IP header to be received or sent.то есть если PF_PACKET то от програмиста требуется составить IP или какой-нибудь свой заголовок
а если PF_INET то IP заголовок уже есть и надо добавить заголовок следующего уровеня TCP/UDP или что-нибудь своёman -s7 raw
raw_socket = socket(PF_INET, SOCK_RAW, int protocol);
Raw sockets allow new IPv4 protocols to be implemented in user space. A raw socket receives or sends the raw datagram not including link level headers.думаю, что socket(PF_INET, SOCK_RAW, int protocol); будет вполне достаточно.
>то есть если PF_PACKET то от програмиста требуется составить IP или какой-нибудь
>свой заголовок
>а если PF_INET то IP заголовок уже есть и надо добавить заголовок
>следующего уровеня TCP/UDP или что-нибудь своё
>
>man -s7 raw
>raw_socket = socket(PF_INET, SOCK_RAW, int protocol);
>Raw sockets allow new IPv4 protocols to be implemented in user space.
> A raw socket receives or sends the raw datagram not
>including link level headers.
>
>думаю, что socket(PF_INET, SOCK_RAW, int protocol); будет вполне достаточно.Спасибо, стало яснее. И еще вопрос, касающийся выбора поля protocol. В чем существенная разница между IPPROTO_RAW и например ETH_P_IP, ведь в обоих случаях получим доступ к IP уровню ?
Разница в том, что в первом случае это поле IP заголовка, а во втором - Ethernet. Что хорошо видно, если посмотреть, где определены эти константы: первая рядом с константами IPPROTO_TCP, IPPROTO_UDP и т.д., а вторая рядом с ETH_P_IPX, ETH_P_ARP, ETH_P_RARP, и т.д. Не говоря уже о заголовочниках, в которых они определены и о коментариях в этих заголовочниках...
Спасибо за ответы. Теперь пытаюсь сваять примитивный код на основе "сырых" сокетов. Задача простая: слушать определенный интерфейс, и если появилась какая-то активность, то сообщить что-то на консоль. Делаю так:...
int main(void)
{
int sock;
ssize_t n;
unsigned char buffer[BUFSIZE];
struct ifreq req;if ((sock = socket(PF_PACKET, SOCK_RAW, htons(IPPROTO_RAW))) < 0) {
perror("socket() error");
return -1;
}/* bind device to the socket */
strncpy(req.ifr_name, "eth0", sizeof(req.ifr_name));
if (ioctl(sock, SIOCGIFFLAGS, &req) < 0) {
perror("ioctl() error");
return -1;
}/* set the interface promiscous mode */
req.ifr_flags |= IFF_PROMISC;
if (ioctl(sock, SIOCSIFFLAGS, &req) < 0) {
perror("ioctl() error");
return -1;
}printf("Initialized !\n");
while (1) {
if ( (n = read(sock, buffer, BUFSIZE)) <= 0 ) {
printf("read() <= 0\n");
continue;
}
fprintf(stdout, "got %d bytes packet\n", n); fflush(stdout);
}return 0;
}Компилирую на линуксе (ядро 2.4.20) без ошибок и варнингов:
gcc -Wall -g -ansi -o raw raw.cЗапускаю, с другой консоли пускаю пинг через интерфейс "eth0" и тишина, мое приложение никак не реагирует.
В чем ошибка?
>Спасибо за ответы. Теперь пытаюсь сваять примитивный код на основе "сырых" сокетов.
>Задача простая: слушать определенный интерфейс, и если появилась какая-то активность, то
>сообщить что-то на консоль. Делаю так:
>
>...
>int main(void)
>{
> int sock;
> ssize_t n;
> unsigned char buffer[BUFSIZE];
//ненада
> struct ifreq req;
>
> if ((sock = socket(PF_PACKET, SOCK_RAW, htons(IPPROTO_RAW))) < 0) {
сырых или пакетных?
ты пользуешь пакетный
man 7 ip
--
raw_socket = socket(PF_INET, SOCK_RAW, protocol);
--
man packet
--
packet_socket = socket(PF_PACKET, int socket_type, int protocol);
--
вместо PF_PACKET поставь PF_INET
с сырым сокетом моно работать как с обычным - socket потом например setsockopt потом bind а потом recvfrom и sendto
и сё
вообще в int protocol не нада преобразовывать порядок бит из хостового в сетевой
т. е. не
htons(IPPROTO_RAW)
а
IPPROTO_RAW
"as is"
> perror("socket() error");
> return -1;
> }
>
вот для сырого сокета это тож ненада
/*
> /* bind device to the socket */
> strncpy(req.ifr_name, "eth0", sizeof(req.ifr_name));
> if (ioctl(sock, SIOCGIFFLAGS, &req) < 0) {
> perror("ioctl() error");
> return -1;
> }
>
> /* set the interface promiscous mode */
> req.ifr_flags |= IFF_PROMISC;
> if (ioctl(sock, SIOCSIFFLAGS, &req) < 0) {
> perror("ioctl() error");
> return -1;
> }
>
*/
> printf("Initialized !\n");
>
> while (1) {
> if ( (n = read(sock, buffer, BUFSIZE)) <=
>0 ) {
> printf("read() <= 0\n");
> continue;
> }
> fprintf(stdout, "got %d bytes packet\n", n); fflush(stdout);
> }
>
> return 0;
>}
>
>Компилирую на линуксе (ядро 2.4.20) без ошибок и варнингов:
>gcc -Wall -g -ansi -o raw raw.c
>
>Запускаю, с другой консоли пускаю пинг через интерфейс "eth0" и тишина, мое
>приложение никак не реагирует.
>
>В чем ошибка?