Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги хакеры / Защита_от_взлома_сокеты,_эксплойты,_shell_код_Фостер_Дж_

.pdf
Скачиваний:
14
Добавлен:
19.04.2024
Размер:
3.68 Mб
Скачать

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

Клиенты и серверы для протокола UDP 161

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

p

 

-x cha

 

 

 

 

 

 

 

-xchâàòüa

структуру sockaddr_in и как посылать UDP-датаграммы с помощью фун-

 

 

e

 

 

 

 

df

 

 

n

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

êöèè send().

Анализ

В строке 15 включается файл arpa/inet.h, содержащий прототипы функций преобразования адресов IPv4 в точечно-десятичную нотацию и обратно.

В строках 17 и 18 с помощью директив препроцессора определяются IP-адрес и порт получателя, то есть конечная точка, в которую будут направляться UDP-датаграммы.

В строках 23–26 объявляются локальные переменные. В структуру sin òèïà struct sockaddr_in будет помещен IP-адрес и порт получателя.

В строках 27–32 с помощью функции socket() создается UDP-сокет. Процедура не отличается от встретившейся в примере 3.4.

В строках 37 в поле sin_family структуры sin помещается константа AF_INET, определяющая адресное семейство. При работе с протоколом UDP всегда следует задавать именно это семейство.

В строке 38 в поле sin_port записывается номер удаленного порта, в который должна быть доставлена датаграмма. Предварительно номер порта передается функции htons(), которая преобразует байты целого числа в сетевой порядок, чтобы обеспечить переносимость. По определению, сетевой порядок – это «big-endian» (старший байт слева). Поэтому, на компьютерах, где целые числа изначально представлены в таком виде, функция htons() ничего не делает. Если же машинный порядок – «little-endian» (старший байт справа), то она переставляет младший и старший байты.

В строке 39 адрес получателя, заданный в точечно-десятичной нотации, преобразуется в беззнаковое целое число с помощью функции inet_addr(), после чего записывается в поле sin_addr.s_addr структуры sockaddr_in. Функция inet_addr() возвращает целое без знака, представленное в сетевом порядке байтов. Получив на входе некорректный адрес, функция вернет константу INADDR_NONE, являющуюся признаком ошибки.

В строке 41 вызывается функция connect(), которая ассоциирует с сокетом адрес, заданный в структуре sockaddr_in. Если она завершится успешно, то можно приступать к обмену данными через сокет, который продолжается до тех пор, пока не возникнет ошибка или одна из сторон не вызовет функцию close(). В случае ошибки connect() вернет –1.

В строке 48 буфер размером 100 байтов заполняется символами A. Ýòî

данные, которые мы отправим получателю через сокет.

162 Глава 3. BSD сокеты

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

В строке 50 для отправки данных вызывается функция send(). Åå ïåð--x cha

 

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

вый параметр – это дескриптор сокета, второй – указатель на буфер, содержащий данные, третий – размер этого буфера в байтах. Четвертый параметр может содержать различные флаги, которые в данном примере не используются. Функция send() в случае успеха возвращает число отправленных байтов, а в случае ошибки – отрицательное число.

Âпримере 3.6 демонстрируется отправка UDP-датаграммы, когда IP-адрес

èномер порта задаются во время выполнения.

Пример 3.6. Отправка UDP*датаграммы функцией sendto() (udp3.c)

1 /*

2 * udp3.c

3*

4* отправка UDP-датаграммы через сокет

5* с помощью функции sendto().

6 * Пример 3.

7*

8 * foster <jamescfoster@gmail.com>

9 */

10

11 #include <stdio.h>

12

13 #include <sys/socket.h>

14 #include <netinet/in.h>

15 #include <arpa/inet.h>

16

17#define UDP3_DST_ADDR "127.0.0.1"

18#define UDP3_DST_PORT 1234

19

20int

21main(void)

22{

23struct sockaddr_in sin;

24char buf[100];

25int sock = 0;

26int ret = 0;

27

28sock = socket(AF_INET, SOCK_DGRAM, 0);

29if(sock < 0)

30{

31printf("ошибка socket().\n");

32return(1);

33}

34

35

memset(&sin, 0x0, sizeof(sin));

36

 

 

37

sin.sin_family

= AF_INET;

 

 

 

 

hang

e

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

d

 

 

F

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

w Click

 

 

 

 

m

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

o

 

 

.

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

e

 

 

 

 

df-xch38an

 

 

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55 }

sin.sin_port sin.sin_addr.s_addr

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

Клиенты и серверы для протокола UDP 163

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

 

 

 

 

.c

 

= htons(UDP3_DST_PORT);

 

p

 

 

 

 

 

e

 

 

 

 

 

 

g

 

 

 

 

 

df-x chan

 

 

 

 

= inet_addr(UDP3_DST_ADDR);

memset(buf, 'A', 100);

ret = sendto(sock, buf, 100, 0,

(struct sockaddr *) &sin, sizeof(sin)); if(ret != 100)

{

printf("ошибка sendto().\n"); return(1);

}

close(sock);

printf("sendto()завершилась успешно.\n");

return(0);

Компиляция

obsd32# gcc -o udp3 udp3.c

Пример исполнения

obsd32# ./udp3

sendto() завершилась успешно.

Анализ

В программе udp3.c показан альтернативный способ отправки данных: с помощью функции sendto(). Вместо того чтобы один раз задать IP-адрес и номер порта, вызвав connect(), мы задаем их при каждом вызове sendto(), передавая в качестве пятого параметра указатель на структуру sockaddr_in. Тем самым единственный дескриптор можно использовать для обмена данными с разными хостами. Функция sendto() полезна, когда данные нужно посылать разным получателям, например, при реализации сканера, работающего по протоколу UDP.

Единственное отличие примера udp3.c îò udp2.c в том, что отсутствует вызов connect(), а вместо send() вызывается sendto(). В примере 3.7 демонстрируется прием UDP-датаграммы с помощью функции recvfrom().

Пример 3.7. Прием UDP*датаграммы (udp4.c)

1/*

2 * udp4.c

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

 

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

 

to

 

 

164

Глава 3. BSD сокеты

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

 

.

 

 

 

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

3

 

 

 

 

df-xchan

e

*

 

 

 

 

 

4* прием UDP-датаграммы с помощью

5* функции recvfrom().

6 * Пример 4.

7*

8 * foster <jamescfoster@gmail.com>

9 */

10

11 #include <stdio.h>

12

13 #include <sys/socket.h>

14 #include <netinet/in.h>

15

16 #define UDP4_PORT 1234

17

18int

19main(void)

20{

21struct sockaddr_in sin;

22char buf[100];

23int sock = 0;

24int ret = 0;

25

26sock = socket(AF_INET, SOCK_DGRAM, 0);

27if(sock < 0)

28{

29printf("ошибка socket().\n");

30return(1);

31}

32

33

memset(&sin, 0x0, sizeof(sin));

34

 

 

35

sin.sin_family

= AF_INET;

36

sin.sin_port

= htons(UDP4_PORT);

37

sin.sin_addr.s_addr = INADDR_ANY;

38

 

 

39ret = bind(sock, (struct sockaddr *) &sin, sizeof(sin));

40if(ret < 0)

41{

42printf("ошибка bind().\n");

43return(1);

44}

45

46ret = recvfrom(sock, buf, 100, 0, NULL, NULL);

47if(ret < 0)

48{

49printf("ошибка recvfrom().\n");

50return(1);

51}

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

-

 

 

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

 

 

 

e

 

 

 

 

d

 

 

xch52

 

 

 

 

 

 

 

f-

 

an

 

 

 

 

53 close (sock);

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

Клиенты и серверы для протокола UDP 165

 

to

 

 

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

54 printf("recvfrom() завершилась успешно.\n");

55

56return(0);

57}

Компиляция

obsd32# gcc -o udp4 udp4.c

Пример исполнения

obsd32# ./udp4 & [1] 18864

obsd32# ./udp3

recvfrom() завершилась успешно. sendto() завершилась успешно.

[1] + Done ./udp4

Эта программа создает UDP-сокет, привязывает его к порту 1234 и ждет поступления одной датаграммы. В примере выполнения мы сначала запускаем udp4, а затем udp3. Программа udp3 отправляет единственную датаграмму udp4.

Анализ

В строках 13 и 14 включаются заголовочные файлы sys/socket.h è netinet/in.h.

В строке 16 определяется порт (1234), к которому будет привязан сокет.

В строке 26 с помощью функции socket() создается сокет точно так же, как и в предыдущих примерах.

В строках 32–36 в структуру sockaddr_in записываются IP-адрес и номер порта локальной оконечной точки. Поля sin_family è sin_port заполняются как и раньше. В поле sin_addr.s_addr записывается константа INADDR_ANY, которая говорит, что в сокет должны направляться датаграммы, поступившие на любой сетевой интерфейс данного компьютера. Так, если компьютер оборудован двумя сетевыми интерфейсами, то сокет привязывается к обоим. При желании сокет можно привязать к конкретному интерфейсу, для этого нужно занести в поле sin_addr.s_addr назначенный ему IP-адрес.

В строке 39 функция bind() привязывает сокет к оконечной точке, определяемой содержимым структуры sockaddr_in. Первый параметр bind() – это дескриптор сокета, второй – адрес структуры sockaddr_in,

который должен быть приведен к типу struct sockaddr. Третий параметр

166 Глава 3. BSD сокеты

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

должен содержать длину структуры sockaddr_in в байтах. Если bind() çà--x cha

 

e

 

 

 

 

df

 

 

n

 

 

 

 

 

 

 

 

 

 

вершится успешно, она вернет 0, в случае ошибки – отрицательное зна- чение.

В строке 46 вызывается функция recvfrom() для приема одной датаграммы. Ее первым параметром является дескриптор ранее привязанного сокета, вторым – указатель на массив символов, в который будут помещены принятые данные, третьим – длина этого массива в байтах. Четвертым параметром может быть адрес структуры sockaddr_in, приведенный к типу struct sockaddr, а пятым – указатель на целое число, содержащее длину структуры sockaddr_in в байтах. Если четвертый и пятый параметр заданы (не равны NULL), то в эту структуру sockaddr_in будут помещены IP-адрес и порт отправителя датаграммы.

В строке 53 сокет вызывается функция close(), которая закрывает сокет, после чего он уже не может использоваться для приема данных.

Опции сокетов

В состав API BSD-сокетов входит много функций для отправки и приема данных. Хотя их действий по умолчанию достаточно для реализации типичной функциональности, иногда приходится изменять некоторые аспекты работы сокетов. Для этого служит функция setsockopt().

Эта функция позволяет менять параметры на разных уровнях стека протоколов. Если речь идет о семействе AF_INET, то можно модифицировать поведение как самого сокета, так и протоколов UDP, TCP, ICMP и так далее.

Чаще всего опции применяются для изменения параметров самого сокета. Можно задать правила обработки ошибок, размеры буферов, интерпретацию адресов и портов, а также величины таймаутов при приеме и передаче данных. Из всех вышеперечисленных возможностей обычно используется опция SO_RCVTIMEO для задания таймаута при чтении данных функциями read(), recv() è recvfrom().

По умолчанию функции read(), recv() è recvfrom() выполняют блокирующее чтение, то есть функция будет ждать до тех пор, пока в сокет не поступят данные или не произойдет ошибка. Такое поведение нежелательно, если программа должна выполнить некоторое действие, когда данные не поступают вовремя. Тут-то и приходит на помощь опция SO_RCVTIMEO, которая позволяет указать, сколько времени сокет может ждать данных, прежде чем вернуть управление вызывающей программе. В примере 3.8 показано, как с помощью функции setsockopt() установить опцию SO_RCVTIMEO для UDPсокета.

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

 

 

 

.c

 

3.8.

 

 

p

 

-xchПримерa

 

 

 

 

 

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

Опции сокетов 167

 

to

 

 

 

 

 

 

 

 

 

 

 

 

 

w Click

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

Установка опций сокета с помощью функции setsockopt()

 

.

 

-x cha

 

.c

 

 

 

p

 

g

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

 

 

 

 

1 /*

2 * makeudpsock()

3 *

4 *

5*/

6 int makeudpsock (char *dst, unsigned short port)

7 {

8struct sockaddr_in sin;

9struct timeval tv;

10unsigned int taddr = 0;

11int sock = 0;

12int ret = 0;

13

14taddr = inet_addr(targ);

15if(taddr == INADDR_NONE)

16{

17printf("ошибка inet_addr().\n");

18return(-1);

19}

20

21sock = socket(AF_INET, SOCK_DGRAM, 0);

22if(sock < 0)

23{

24printf("ошибка socket().\n");

25return(-1);

26}

27

28

memset(&sin, 0x0, sizeof(sin));

29

 

 

30

sin.sin_family

= AF_INET;

31

sin.sin_port

= htons(port);

32

sin.sin_addr.s_addr = taddr;

33

 

 

34ret = connect(sock, (struct sockaddr *) &sin,

35sizeof(sin));

36if(ret < 0)

37{

38printf("ошибка connect().\n");

39return(-1);

40}

41

42

memset(&tv, 0x00, sizeof(tv));

43

 

44

tv.tv_sec = 10;

45

 

46

ret = setsockopt(sock, SOL_SOCKET,

47

SO_RCVTIMEO, &tv, sizeof(tv));

48

if(ret < 0)

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

168

Глава 3. BSD сокеты

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

 

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

e

 

{

 

 

 

df-xchan

49

 

 

 

 

 

 

 

 

50

printf("ошибка setsockopt().\n");

 

 

 

 

 

 

 

 

51

return(-1);

 

 

 

 

 

 

 

 

52

}

 

 

 

 

 

 

 

 

53

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha

 

 

 

 

54return(sock);

55}

Âэтом примере с помощью функций socket() è connect() создается и ассоциируется с удаленной оконечной точкой UDP-сокет. Затем вызывается функция setsockopt(), которая задает величину таймаута при приеме данных. Эта величина предварительно записывается в структуру timeval. Функция makeudpsock() возвращает дескриптор вновь созданного сокета.

Анализ

В строках 7–39 с помощью функций socket() è connect() создается новый сокет. Эта процедура уже рассматривалась выше;

В строках 45 и 46 вызывается функция setsockopt(). Первым параметром ей передается дескриптор сокета, для которого нужно задать опции. Второй параметр – это уровень протокола, на котором действуют задаваемые опции. В данном случае константа SOL_SOCKET сообщает, что задается опция на уровне самого сокета. Третий параметр – это собственно опция; мы указали целочисленную константу SO_RCVTIMEO. Четвертый и пятый параметры функции зависят от того, какой уровень и опция переданы соответственно во втором и третьем параметрах. В случае SOL_SOCKET è SO_RCVTIMEO в четвертом параметре следует задать указатель на структуру timeval и ее размер в байтах. Поля tv_sec è tv_usec этой структуры задают число секунд и микросекунд в значении таймаута.

Примечание

Чтобы задать опции на уровне протокола IP, вместо константы SOL_SOCKET нужно указать IPPROTO_IP. Протоколу UDP соответствует константа IPPROTO_UDP, а протоколу TCP – константа IPPROTO_TCP. Константы, определяющие уровень и имена опций, находятся в заго ловочных файлах sys/socket.h и netinet/in.h.

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

X

 

 

 

 

 

 

 

 

 

X

 

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

 

t

 

 

 

F

 

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

D

 

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

 

Сканирование сети с помощью UDP сокетов 169

 

to

 

 

 

 

 

 

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

m

 

w Click

 

 

 

 

 

 

 

m

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

 

w

 

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

g

.c

 

 

 

.

 

 

 

 

g

.c

 

 

 

p

 

 

 

 

 

 

 

 

 

 

p

 

 

 

 

 

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

 

Сканирование сети

 

 

 

 

-x cha

 

 

 

 

 

 

 

 

 

-xcha

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

с помощью UDP сокетов

В этом разделе мы рассмотрим полную программу, которая, пользуясь протоколом UDP и API сокетов, реализует сканирование имен сообществ (community name), определенных в протоколе SNMP (Simple Network Management Protocol – простой протокол управления сетью). Протокол SNMP широко распространен и применяется для получения и задания различных параметров компьютеров и устройств, подключенных к сети. Для этого узлу посылаются команды SNMP GetRequest è SetRequest, инкапсулированные в UDP-датаграммы.

Для получения параметра хост-отправитель посылает хосту-получателю команду GetRequest. Получатель проверяет корректность запроса и возвращает отправителю в составе UDP-датаграммы ответ GetResponse вместе с данными исходного запроса. В случае же запроса SetRequest получатель проверяет его корректность и вносит необходимые изменения в конфигурацию.

Получать или изменять можно разнообразные параметры, в том числе имя удаленного хоста, IP-адрес и статистику. Программа, реагирующая на SNMP-запросы, называется агентом протокола SNMP. Агент привязывает свой сокет к порту 161 и ожидает поступления запросов GetRequest è SetRequest. Требуется, чтобы в полученном запросе было задано имя сообщества, известное агенту SNMP. Оно служит аналогом пароля, поскольку запросы, не содержащего корректного имени сообщества, игнорируются.

На наше счастье, большинство программ-агентов поставляются с предварительно сконфигурированным именем сообщества «public». Поэтому мы может узнать о наличии в сети множества устройств, поддерживающих протокол SNMP. В примере 3.9 демонстрируется, как с помощью UDP-сокетов можно отправить запрос GetRequest для получения имени удаленного хоста и принять соответствующий ответ.

Пример 3.9. Сканер SNMP (snmp1.c)

1 /*

2 * snmp1.c

3*

4 * Сканер snmp scanner. Пример 1.

5*

6 * foster <jamescfoster@gmail.com>

7 */

8

9 #include <stdio.h>

10 #include <stdlib.h>

11 #include <unistd.h>

 

 

 

 

hang

e

 

 

 

 

 

 

 

 

C

 

E

 

 

 

 

 

 

X

 

 

 

 

 

 

 

 

-

 

 

 

 

d

 

 

 

F

 

 

 

 

 

 

t

 

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

 

r

 

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

 

to

 

 

170 Глава 3. BSD сокеты

w Click

 

 

 

 

 

 

 

 

 

 

 

 

 

m

 

w

 

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

 

.

 

 

 

 

 

.c

 

 

 

 

p

 

 

 

 

g

 

 

 

 

 

 

 

 

 

 

e

 

 

 

 

 

df-xchan

12 #include <string.h>

 

 

 

 

 

 

 

 

13 #include <ctype.h>

 

 

 

 

 

 

 

 

14

 

 

 

 

 

 

 

 

 

15 #include <sys/socket.h>

 

 

 

 

 

 

 

 

16 #include <netinet/in.h>

 

 

 

 

 

 

 

 

17 #include <arpa/inet.h>

 

 

 

 

 

 

 

 

18

 

 

 

 

 

 

 

 

 

19 #define

SNMP1_DEF_PORT 161

 

 

 

 

 

 

 

 

20 #define

SNMP1_DEF_COMN "public"

 

 

 

 

 

 

 

 

21

 

 

 

 

 

 

 

 

 

22 #define

SNMP1_BUF_SIZE 0x0400

 

 

 

 

 

 

 

 

23

 

24/*

25* hexdisp()

26*

27*

28*/

29void hexdisp (char *buf, int len)

30{

31char tmp[16];

32int x = 0;

33int y = 0;

34

35 printf("\n");

36

37for(x=0; x < len; ++x)

38{

39tmp[x % 16] = buf[x];

41if((x + 1) % 16 == 0)

42{

43for(y=0; y < 16; ++y)

44{

45printf("%02X ", tmp[y] & 0xFF);

46}

47for(y=0; y < 16; ++y)

49{

50printf("%c", isprint(tmp[y]) ?

51

tmp[y] : '.');

52}

53printf("\n");

54}

55}

56

57if((x % 16) != 0)

58{

59for(y=0; y < (x % 16); ++y)

60{

61printf("%02X ", tmp[y] & 0xFF);

 

 

 

 

hang

e

 

 

 

 

 

 

 

C

 

E

 

 

 

 

X

 

 

 

 

 

 

-

 

 

 

 

 

d

 

 

F

 

 

 

 

 

 

t

 

 

D

 

 

 

 

 

 

 

i

 

 

 

 

 

 

 

 

 

r

P

 

 

 

 

 

NOW!

o

 

 

 

 

 

 

 

 

 

 

 

 

BUY

 

 

 

 

 

 

to

 

 

 

 

 

w Click

 

 

 

 

 

m

 

 

 

 

 

 

w

 

 

 

 

 

 

 

 

 

 

w

 

 

 

 

 

 

 

o

 

 

.

 

 

 

 

 

.c

 

 

 

p

 

 

 

 

g

 

 

 

 

 

df

 

 

n

e

 

 

 

 

 

-x cha