5 / 9 / 0
Регистрация: 06.03.2015
Сообщений: 19

Прием и отправка "сырых" пакетов в Ethernet

07.12.2024, 12:45. Показов 3256. Ответов 9

Студворк — интернет-сервис помощи студентам
Появилась необходимость отсылать и принимать "сырые" пакеты в сети Ethernet.
Накопипастив кучу кода в интернете и на форуме сваял следующее:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
uses
  ... Sockets;
 
rocedure TForm1.Button1Click(Sender: TObject);
var
  BSocket: Longint;
  BAddr : TInetSockAddr;
  BErr: Longint;
  BArr: array [0..3] of byte;
begin
   BSocket := fpSocket (PF_PACKET, SOCK_RAW, 0);
   if SocketError <> 0 then begin
     // SocketError = 1 => не хватает прав? root!
     ShowMessage('Err socket: ' + IntToStr(SocketError));
     Exit;
   end;
 
   BAddr.sin_family := PF_PACKET;
   BAddr.sin_port := htons($0003);
   //BAddr.sin_port := 0;
   BAddr.sin_addr := StrToNetAddr('192.168.1.2');
   //BAddr.sin_addr.s_addr := 0;
 
   if fpbind(BSocket, @BAddr, SizeOf(BAddr)) <> 0 then begin
     // SYS_EINVAL = 22 (The socket is already bound to an address)
     // SYS_EBADF = 9 (The socket descriptor is invalid)
     ShowMessage('Error bind: ' + IntToStr(SocketError));
     Exit;
   end;
 
   BArr[0] := $AA;
   BArr[1] := $BB;
   BArr[2] := $DD;
   BArr[3] := $EE;
   BErr := fpsend(BSocket, @BArr, 4, 0);
   if BErr < 0 then begin
     ShowMessage('Error send: '+ IntToStr(BErr) + ';' + IntToStr(SocketError));
     Exit;
   end;
end;
запускаю программу через sudo
получаю ошибку при выполнении fpbind(Строка 24): SYS_EINVAL = 22

подскажите пожалуйста, что можно сделать чтобы отправить(а потом и принять) "сырой" пакет в Lazarus?
Полный код проекта: Project001.zip

Ubuntu 20.04, Lazarus 3.4.0, FPC 3.2.2

З.Ы.
на питоне похожая конструкция работает, только для адреса сокета она получает имя устройства а не IP
Рабочий код на питоне: TxRxPy.zip
0
Лучшие ответы (1)
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
07.12.2024, 12:45
Ответы с готовыми решениями:

Прием и отправка пакетов
Всем привет! Нужно отправить определенной структуры пакет серверу на порт 28000. Так выглядит структура пакета: ...

RS232 отправка и прием пакетов
Коллеги, добрый день. Передо мной стала задача, которую я совершенно не могу понять в виду того, что никогда не работал с Com портами....

Отправка и прием TCP пакетов
Здравствуйте, пишу тсп клиент сервер. Все бы ничего но с толкнулся с такой проблемой при отправке клиентом нескольких пакетов с данными...

9
 Аватар для abit
867 / 526 / 148
Регистрация: 03.02.2013
Сообщений: 1,845
10.12.2024, 04:04
Лучший ответ Сообщение было отмечено snegok74 как решение

Решение

Пфффф... PF_PACKET работает на канальном уровне, ему нужно интерфейс скормить типа eth0, структуру запилить sockaddr_ll с MAC вместо sockaddr_in

вообще sin_family := PF_PACKET имеет право? Где вы такое взяли? По логике структура sockaddr_in не может в PF_PACKET, это транспортный уровень

Кликните здесь для просмотра всего текста

Не по теме:

Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
uses
  Classes, SysUtils, BaseUnix, Sockets, Unix;
  
  const
  // Протоколы и константы
  ETH_P_ALL = $0003; // Для приема всех пакетов Ethernet
  SIOCGIFINDEX = $8933; // Код для получения индекса интерфейса
  IFNAMSIZ = 16; // Максимальная длина имени интерфейса
  
  type
  sockaddr_ll = packed record
    sll_family: cuint16;       // Всегда AF_PACKET
    sll_protocol: cuint16;     // Протокол Ethernet (например, $0800 для IPv4)
    sll_ifindex: cint;         // Индекс интерфейса
    sll_hatype: cuint16;       // Аппаратный тип (необязательно)
    sll_pkttype: cuint8;       // Тип пакета (необязательно)
    sll_halen: cuint8;         // Длина аппаратного адреса
    sll_addr: array[0..7] of cuint8; // Аппаратный адрес (MAC)
  end;
  
    ifreq = record
    ifr_name: array[0..IFNAMSIZ-1] of char; // Имя интерфейса
    ifr_ifindex: cint;                      // Индекс интерфейса
    padding: array[0..15] of byte;          // Дополнительное место
  end;
 
var
  BSocket: Longint;
  BAddr: sockaddr_ll;
  BErr: Longint;
  InterfaceIndex: Integer;
  BArr: array [0..13] of byte; // Ethernet frame
  _IfReq: ifreq;
begin
  // Создание RAW-сокета
  BSocket := fpSocket(PF_PACKET, SOCK_RAW, htons($0800)); // $0800 = IPv4
  if BSocket < 0 then
  begin
    Writeln('Error socket: ' + IntToStr(fpgeterrno));
    Exit;
  end;
 
  // Получение индекса сетевого интерфейса (например, eth0)
  FillChar(_IfReq, SizeOf(IfReq), 0);
  StrPLCopy(_IfReq.ifr_name, 'eth0', IFNAMSIZ); // Укажите ваш интерфейс
  if fpIoctl(BSocket, SIOCGIFINDEX, @_IfReq) < 0 then
  begin
    Writeln('Error ioctl: ' + IntToStr(fpgeterrno));
    Exit;
  end;
  InterfaceIndex := _IfReq.ifr_ifindex;
 
  // Настройка адреса sockaddr_ll
  FillChar(BAddr, SizeOf(BAddr), 0);
  BAddr.sll_family := PF_PACKET;
  BAddr.sll_protocol := htons($0800); // Протокол (IPv4)
  BAddr.sll_ifindex := InterfaceIndex;
  BAddr.sll_halen := 6; // Длина MAC-адреса
 
  // Указываем MAC-адрес назначения (пример: FF:FF:FF:FF:FF:FF - широковещание)
  BAddr.sll_addr[0] := $FF;
  BAddr.sll_addr[1] := $FF;
  BAddr.sll_addr[2] := $FF;
  BAddr.sll_addr[3] := $FF;
  BAddr.sll_addr[4] := $FF;
  BAddr.sll_addr[5] := $FF;
 
  // Формирование Ethernet-кадра
  // MAC-адрес назначения (6 байт)
  BArr[0] := $FF; BArr[1] := $FF; BArr[2] := $FF;
  BArr[3] := $FF; BArr[4] := $FF; BArr[5] := $FF;
 
  // MAC-адрес источника (6 байт) – замените на MAC вашего интерфейса
  BArr[6] := $12; BArr[7] := $34; BArr[8] := $56;
  BArr[9] := $78; BArr[10] := $9A; BArr[11] := $BC;
  // Тип протокола (2 байта) – например, $0800 для IPv4
  BArr[12] := $08; BArr[13] := $00;
 
if fpbind(BSocket, @BAddr, SizeOf(BAddr)) <> 0 then begin
     Writeln('Error bind: ' + IntToStr(SocketError));
     Exit;
   end;
 
  // Отправка Ethernet-кадра
  BErr := fpSendTo(BSocket, @BArr, SizeOf(BArr), 0, @BAddr, SizeOf(BAddr));
  if BErr < 0 then
  begin
    WriteLn('Ошибка отправки пакета: ', fpGetErrNo);
    Exit;
  end;
 
  WriteLn('Пакет успешно отправлен!');
 
  // Закрытие сокета
  if fpClose(BSocket) < 0 then
  begin
    WriteLn('Ошибка закрытия сокета: ', fpGetErrNo);
  end;
  
  end.


1
5 / 9 / 0
Регистрация: 06.03.2015
Сообщений: 19
10.12.2024, 12:02  [ТС]
Быстренько обкатал код и .... работает!!!
Abit, спасибище!
Столько тонкостей, вот откуда обычному смертному такое знать!?
0
 Аватар для abit
867 / 526 / 148
Регистрация: 03.02.2013
Сообщений: 1,845
10.12.2024, 15:43
Цитата Сообщение от snegok74 Посмотреть сообщение
Столько тонкостей, вот откуда обычному смертному такое знать!?
так в Linux отличный man сиди да читай хоть целыми днями )))
0
5 / 9 / 0
Регистрация: 06.03.2015
Сообщений: 19
10.12.2024, 17:24  [ТС]
Начал читать man'ы, и вопросов стало только больше)))

Логично, что теперь я пытаюсь собрать инфу обо всех сетевых интерфейсах командой(fpIoctl(BSocket, SIOCGIFCONF, @ifc)) в системе и начал копать ifconf на странице где описана и структура ifreq. И появился закономерный вопрос: зачем поле padding в коде примера? Это только для безопасности, чтобы случайно не переписать что-то в памяти? Почему 16 байт?
Pascal
1
2
3
4
5
ifreq = record
    ifr_name: array[0..IFNAMSIZ-1] of char; // Имя интерфейса
    ifr_ifindex: cint;                      // Индекс интерфейса
    padding: array[0..15] of byte;          // Дополнительное место
  end;
0
 Аватар для abit
867 / 526 / 148
Регистрация: 03.02.2013
Сообщений: 1,845
10.12.2024, 21:03
Цитата Сообщение от snegok74 Посмотреть сообщение
зачем поле padding в коде примера?
сложно сформулировать, но в таком контексте ioctl(socketfd,SIOCGIFCONF,&conf) ядро записывает в буфер массив структур ifreq для всех сетевых интерфейсов в системе, rаждое значение должно быть правильно выравнено в памяти в зависимости от архитектуры, поле ifr_addr (которое обычно является struct sockaddr) может требовать выравнивания, скажем, на границе 4 или 8 байт (тут отошлю к ABI).
padding гарантирует, что каждая структура ifreq в массиве будет выровнена правильно

Цитата Сообщение от snegok74 Посмотреть сообщение
Почему 16 байт?
размер padding зависит от платформы и того, как ядро возвращает данные

struct sockaddr (который используется в ifr_addr) имеет длину 16 байт, выравнивание данных кратно 16 байтам на всем с чем я работал, но вообще там может быть всё что угодно)))
1
5 / 9 / 0
Регистрация: 06.03.2015
Сообщений: 19
10.12.2024, 23:10  [ТС]
Жаль что нельзя выяснить размер структуры в работающей ОСи((
У меня р-р записи оказался 20 байт(Ubuntu 20.04 x64) и как-раз убрав padding, у меня возвращается список всех интерфейсов.
Pascal
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
const
  IFNAMSIZ = 16; // Максимальная длина имени интерфейса
 
...
 
ifreq = record
  ifr_name: array[0..IFNAMSIZ-1] of char; // Имя интерфейса
  ifr_ifindex: cint;                      // Индекс/тип интерфейса
end;
 
ifconf = record
  ifc_len: cint;
  ifc_req: array of ifreq;
end;
 
...
 
BIfReq: ifreq;
BIfconf: ifconf;
 
...
 
// Получение имен сетевых интерфейсов - SIOCGIFCONF
BIfconf.ifc_len := 0;
// получить кол-во байт необходимых для возврата списка интерфейсов
if fpIoctl(BSocket, SIOCGIFCONF, @BIfconf) < 0 then
begin
  ShowMessage('Error ioctl: ' + IntToStr(fpgeterrno));
  Exit;
end;
// выяснить текущий(мой) р-р одной записи ifreq = 20 байт!
RecordSize := SizeOf(ifreq);
// проверить что данные кратны моим записям
if BIfconf.ifc_len mod RecordSize = 0 then
begin
  // посчитать кол-во необходимых записей
  n := BIfconf.ifc_len div RecordSize;
  // задать р-р массива приемника(в моих ifreq'ах)
  SetLength(BIfconf.ifc_req, n);
  // получить данные в мой массив ifreq'ов
  if fpIoctl(BSocket, SIOCGIFCONF, @BIfconf) < 0 then begin
    ShowMessage('Error ioctl: ' + IntToStr(fpgeterrno));
    Exit;
  end;
  // вносить список интерфейсов в ListBox
  for i:=0 to n-1 do
    // имя интерфейса задано символами
    if BIfconf.ifc_req[i].ifr_ifindex = 2 then
      ListBox1.Items.Add(string(BIfconf.ifc_req[i].ifr_name))
    else
    // имя интерфейса задано цифрами - IP
    begin
      s := '';
      for j:=0 to 3 do
      begin
        // выводить четыре числа IP'шника деленные точками
        if j>0 then s := s + '.';
        k := ord(BIfconf.ifc_req[i].ifr_name[j]);
        s := s + IntToStr(k);
      end;
      ListBox1.Items.Add('['+s+']');
    end;
end else
  ShowMessage('Error ioctl: размер записи о сетевых интерфейсах не соответствует этой ОС');
PS
Уважаемый abit, загляни пожалуйста в ЛС, ответь что-нибудь
0
Модератор
10359 / 5633 / 3394
Регистрация: 17.08.2012
Сообщений: 17,195
12.12.2024, 10:45
snegok74, при регистрации на форуме Вы обещали соблюдать правила форума. Пожалуйста, выполняйте Ваше обещание. Обсуждение вопроса темы где-либо ещё, кроме самой темы (в том числе, с использованием ЛС) запрещено. Ссылка на правила есть на любой странице форума.
0
5 / 9 / 0
Регистрация: 06.03.2015
Сообщений: 19
12.12.2024, 22:43  [ТС]
ок.

Добавлено через 3 часа 2 минуты
Хотя..., какой ОК, ни разу не ОК!
Где Вы, Cyborg Drone, увидели обсуждение темы в ЛС?!

Вот что было написано в сообщении, в ЛС.
Abit, спасибо за подробный ответ!
Куда, на пиво/шоколадки, выслать скромную благодарность?
Что то не могу сообразить, каким предложением я нарушил правило форума, там где "спасибо" или пиво с шоколадом запрещено поминать всуе?
0
Модератор
10359 / 5633 / 3394
Регистрация: 17.08.2012
Сообщений: 17,195
13.12.2024, 10:17
А зачем Вы abitу в личку написали? С Новым годом поздравить?
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
13.12.2024, 10:17
Помогаю со студенческими работами здесь

UDP отправка и прием пакетов
Вообщем такая ситуация. Отправляю пакеты объемом по 1 кБайту, пачками по 32 через определенное время (маленькое). Вообщем около 8000...

Библиотека для работы (отправка и прием пакетов) с AMF
Нужен компонент или библиотека для работы(отправка и прием пакетов) с AMF, может есть какие хитрости. QenT, ПравилаИзначальное...

Постоянный прием и отправка пакетов по 2кб, с возможностью остановки и запуска
Что требуется? Постоянный прием и отправка пакетов по 2кб, с возможностью остановки и запуска. Как это реализовать на winform ?

Приём сырых сокетов
Отправляю сырой сокет следующим кодом, но принять никак не могу. ОС: ubuntu //Create a raw socket int s = socket...

Прием и отправка пакетов "Яндексу", исправить код
Помогите найти ошибку в тестовом коде суть программы элементарна, при наборе в браузере 127.0.0.1 должна загружаться страничка яндекса,...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
10
Ответ Создать тему
Опции темы

Новые блоги и статьи
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
Расскажи мне о Мире, бродяга
kumehtar 12.11.2025
— Расскажи мне о Мире, бродяга, Ты же видел моря и метели. Как сменялись короны и стяги, Как эпохи стрелою летели. - Этот мир — это крылья и горы, Снег и пламя, любовь и тревоги, И бескрайние. . .
PowerShell Snippets
iNNOKENTIY21 11.11.2025
Модуль PowerShell 5. 1+ : Snippets. psm1 У меня модуль расположен в пользовательской папке модулей, по умолчанию: \Documents\WindowsPowerShell\Modules\Snippets\ А в самом низу файла-профиля. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru