Могу рассказать ... и даже показать

, как произвести перехват любого сетевого системного вызова:
- находим таблицу системных вызовов sys_call_table
- в позиции __NR_socketcall = 102 таблицы лежит адрес обработчика sys_socketcall (sys_call_table[ __NR_socketcall ])
- сохраняем его как old_sys_socketcall
- а в sys_call_table[ __NR_socketcall ] записываем адрес old_sys_socketcall() :
asmlinkage long new_sys_socketcall( int call, unsigned long __user *args ) {
long ret;
if( SYS_CONNECT == call || SYS_ACCEPT == call )
LOG( "new_sys_socketcall before cod=%d\n", call );
ret = old_sys_socketcall( call, args );
if( SYS_CONNECT == call || SYS_ACCEPT == call )
LOG( "new_sys_socketcall after cod=%d\n", call );
// sys_accept & sys_connect` are exported
// можно вызывать: long aret = sys_accept( 1, (struct sockaddr __user*)args, 0 );
return ret;
}
EXPORT_SYMBOL( new_sys_socketcall );
- при записи в sys_call_table нужно снять read-only через MMU с страницы RAM размещения таблицы ... это делается аппаратно через скрытый системный регистр процессора CR0.
Вот, собственно, и всё - вот они все наши сетевые syscall-ы в кулаке ;-) .
Пользователь решил продолжить мысль [time]26 Июнь 2015, 11:17:41[/time]:
Почти случайно, в дебрях интернета

, разыскалась вот такая заметка:
sys socketcall: Network systems calls on Linux.
Daniel No´e
April 9, 2008
Насколько я помню, автор - это один из активных разработчиков сетевой подсистемы Linux ... это имя часто мелькает в комментариях исходного кода ядра.
Там есть весьма любопытные вещи:
1. Ну, про то, что а одних аппаратных архитектурах сделанно вот так, через socketcall (через задницу), а в других нормально, просто как все системные вызовы - это и в man написано. Но автор здесь утверждает, что в i386 сделано через задницу, а в X86_64 - нормально, через sys_call_table (man пишет обратное). Но и в X86_64 сохранён i386. Зачем и это сделано автор (как один из разработчиков) выказывает только
догадки ... что, наверное, из-за совместимости с 32-бит приложениями.
2. Но он подробно описывает технику происходящего:
-
все параметры
любого сетевого ситемного вызова плотно пакуются друг за другом в один массив (не взирая, что для accepr, например, 1-й это целый дескриптор, 2-й - указатель struct sockaddr*, а 3-й - указатель на целую длину ... по барабану, всех пакуем вместе ... "доктор строгий - сказал в морг, значит в морг");
- потом всё это уродство одним параметром указателя на этот массив заталкивается в параметр (2-й) socketcall и делается системный вызов...
- в ядре хранится массив (для каждой сетевой операции) длины, которую нужно тупо скопировать из userspace ... байт за байтом не взирая указатель это или целое ...
- а отом каждый сетевой вызов сам разберётся, по порядку, какой элемент этого массива является его очередным параметром вызова...
И эти люди запрещают мне ковыряться в носу!

3. Наконец сам автор-разработчик говорит, что это уродливая, мол, схема в свете современных представлений объектно-ориентированного и т.д.

. Но так, мол, получилось.
Эта публикация многое проясняет.
И будет просто необходима каждому, кто как-то свяжется с программированием вокруг сетевой подсистемы Linux.
Пользователь решил продолжить мысль [time]27 Июнь 2015, 00:13:13[/time]:
Всё!
Сделано...
Это фактически микро-прототип распределённого файервола, который перехватывает контроль над системными вызовами connect() & accept() Linux, и может запретить как подключения TCP
из определённого IP, так и подключения
к определённому IP.
Я показываю этот пример не из-за его функциональности (это если кто захочет - возитесь сами), а ту технику, как в Linux можно подменить любой системный вызов, и в том числе и сетевые. Об этом часто спрашивают. Дальнейшее продвижение самого этого проекта уже продолжать показывать не буду.