Напишу полноценный DHCP сервер работающий с SQL СУБД.

Технические вопросы по UTM 5.0
Ответить

Как по вашему, нужен-ли кроссплатформенный DHCP сервер хранящий конфигурацию SQL БД?

Да.
71
79%
Нет.
10
11%
Затрудняюсь ответить.
9
10%
 
Всего голосов: 90

starchik
Сообщения: 461
Зарегистрирован: Сб ноя 22, 2008 22:07

Сообщение starchik »

тоже интересен данный вопрос

Arti
Сообщения: 266
Зарегистрирован: Пн окт 01, 2007 02:44

Сообщение Arti »

Если не делать полноценный сервер, а расчитанный на работу с релеем, (не нужно лезть на канальный уровень), при этом если схема "один порт - один адрес" то тут делать нечего.

основной процесс типа такого:

Код: Выделить всё

#define SERVADDR "10.255.255.254"
#define SERVPORT 67

. . .
	bzero ( &serveraddr, sizeof(serveraddr));
	serveraddr.sin_family = AF_INET;
	inet_pton (AF_INET, text_addr, &serveraddr.sin_addr.s_addr);
	serveraddr.sin_port = htons ( SERVPORT );

	bzero ( &clientadr, sizeof(clientadr));


	if&#40;&#40;sockfd = socket&#40;PF_INET, SOCK_DGRAM, 0&#41;&#41; < 0&#41;&#123;
		perror&#40;NULL&#41;;
		return -1;
	&#125;

	if &#40; bind &#40;sockfd, &#40;struct sockaddr *&#41;&serveraddr, sizeof&#40;serveraddr&#41;&#41; < 0&#41;&#123;
		perror&#40;NULL&#41;;
		return -1;
	&#125;
. . .

	for &#40;;;&#41; &#123;
		printf &#40;"ожидание\n"&#41;;
		n = recvfrom &#40;sockfd, &#40;void *&#41;&mesg, DHCP_OPTION_LEN, 0, &#40;struct sockaddr *&#41;&clientadr, &len&#41;;
		printf &#40;"пакет получен\n"&#41;;

		switch &#40; check_options_id &#40;&mesg, n&#41; &#41; &#123;
			case DHCPDISCOVER &#58;
				prepare_dhcp_msg &#40;&mesg, DHCPOFFER&#41;;
				break;
			case DHCPREQUEST  &#58;
				prepare_dhcp_msg  &#40;&mesg, DHCPACK&#41;;
				break;
			case DHCPINFORM   &#58;
				prepare_dhcp_msg  &#40;&mesg, DHCPACK&#41;;
				break;
			case DHCPRELEASE  &#58;
				printf &#40;"не реализовано DHCPRELEASE\n"&#41;;
				break;
			case DHCPDECLINE  &#58;
				printf &#40;"не реализовано DHCPDECLINE\n"&#41;;
				break;
			default&#58;
				continue;
		&#125;

		printf &#40;"оправка сообщения\n"&#41;;
		
		inet_ntop &#40;clientadr.sin_family, &clientadr.sin_addr.s_addr, addr_temp, sizeof &#40;addr_temp&#41;&#41;;
 		printf &#40;"Адрес релая %s\n", addr_temp&#41;;

		clientadr.sin_port = htons &#40; SERVPORT &#41;;
		if&#40; sendto &#40;sockfd, &#40;void *&#41;&mesg, DHCP_OPTION_LEN, 0, &#40;struct sockaddr *&#41;&clientadr, sizeof&#40;clientadr&#41;&#41; < 0&#41;&#123;
			perror&#40;NULL&#41;;
			return &#40;1&#41;;
		&#125;
	&#125;
82 опцию можно распарсить так (это длинк, по-хорошему нужно делать боле универсально):

Код: Выделить всё

int
op_82_parse &#40; uint8_t *op_82, int max_lent&#41;
&#123;
	int  i = 0 ,j = 0;
	uint8_t	op_82_lent = *op_82, sub_op, sub_op_lent, *circ_id, circ_id_lent, *rem_id, rem_id_lent, port;
	uint16_t vlan;

	printf &#40;"_________op_82_parse_____\n"&#41;;

	op_82++;
	while &#40;i < op_82_lent &#41; &#123;

		sub_op = op_82&#91;i&#93;;
		if &#40; &#40; sub_op_lent = op_82&#91;++i&#93; &#41; > &#40;op_82_lent - i&#41; &#41; &#123;
			printf &#40;"неверная длинна подопции %d\n", sub_op&#41;;
			return -1;
		&#125;

		i++;

		switch &#40; sub_op &#41; &#123;
			case 1 &#58;
				circ_id_lent = sub_op_lent;
				circ_id = &#40;op_82 + i&#41;;
				break;
			case 2 &#58;
				rem_id_lent = sub_op_lent;
				rem_id = &#40;op_82 + i&#41;;
				break;
		&#125;
		i += sub_op_lent;
	&#125;

	vlan = ntohs &#40;*&#40;&#40;uint16_t*&#41;&#40;circ_id + 2&#41;&#41;&#41;;
	printf &#40;"___unit&#58;%d port&#58;%d vlan&#58;%d\n",circ_id&#91;4&#93;, circ_id&#91;5&#93;, vlan&#41;;
	for &#40;j=0; j < circ_id_lent; j++&#41; &#123;
		printf &#40;"%02x ",circ_id&#91;j&#93;&#41;;
	&#125;
	printf &#40;"\n"&#41;;
	for &#40;j=0; j < rem_id_lent; j++&#41; &#123;
		printf &#40;"%02x ",rem_id&#91;j&#93;&#41;;
	&#125;
	printf &#40;"\n"&#41;;
	
	return 0;
&#125;
нужно тока парсить опции например так (магик-куку луше конешно вынести):

Код: Выделить всё

unsigned char 
check_options_id &#40; struct dhcp_packet *message, int msg_lent&#41;
&#123;
	unsigned char 	*options = message->options, magic_cookie&#91;&#93; = &#123;99, 130, 83, 99&#125;,
			curr_op, o53;
	int i = 0;

	for &#40;; options&#91;i&#93; == magic_cookie&#91;i&#93; && i < 4; i++ &#41;;
	
	if &#40; i < 4  &#41;&#123;
		printf &#40;"Не DHCP пакетик\n"&#41;;
		return 0;
	&#125;

	for &#40;; options&#91;i&#93; != DHO_END && i < msg_lent; i++&#41;&#123;
		printf &#40;"нашли опцию %d\n", options&#91;i&#93; &#41;;
		if &#40; curr_op = options&#91;i&#93; &#41;&#123;	 
			i++;
			switch &#40;curr_op&#41; &#123;
				case DHO_DHCP_MESSAGE_TYPE&#58;
					o53 = options&#91;i+1&#93;;
					break;
				case DHO_DHCP_AGENT_OPTIONS&#58;
					op_82_parse &#40; &#40;options + i&#41;, &#40;msg_lent - i&#41;&#41;;
					break;
			&#125;
			i += options&#91;i&#93;;
		&#125;
		else
			i++;
	&#125;

	print_options &#40;message&#41;;

	return o53;
	
&#125;
сама структура пакета берется из isc:

Код: Выделить всё

struct dhcp_packet &#123;
  	u_int8_t  op;		/* 0&#58; Message opcode/type */
	u_int8_t  htype;	/* 1&#58; Hardware addr type &#40;net/if_types.h&#41; */
	u_int8_t  hlen;		/* 2&#58; Hardware addr length */
	u_int8_t  hops;		/* 3&#58; Number of relay agent hops from client */
	u_int32_t xid;		/* 4&#58; Transaction ID */
	u_int16_t secs;		/* 8&#58; Seconds since client started looking */
	u_int16_t flags;	/* 10&#58; Flag bits */
	struct in_addr ciaddr;	/* 12&#58; Client IP address &#40;if already in use&#41; */
	struct in_addr yiaddr;	/* 16&#58; Client IP address */
	struct in_addr siaddr;	/* 18&#58; IP address of next server to talk to */
	struct in_addr giaddr;	/* 20&#58; DHCP relay agent IP address */
	unsigned char chaddr &#91;16&#93;;	/* 24&#58; Client hardware address */
	char sname &#91;DHCP_SNAME_LEN&#93;;	/* 40&#58; Server name */
	char file &#91;DHCP_FILE_LEN&#93;;	/* 104&#58; Boot filename */
	unsigned char options &#91;DHCP_OPTION_LEN&#93;;
				/* 212&#58; Optional parameters
				   &#40;actual length dependent on MTU&#41;. */
&#125;;
В общем-то это практически всё :) - осталось тока генерить пакет из sql. Полностью свою реализацию не показываю - больно она кривая... Года полтара назад забросил так и не закончив.

RomanCh
Сообщения: 20
Зарегистрирован: Вт авг 18, 2009 16:54
Контактная информация:

Сообщение RomanCh »

И так, я снова с вами.
hellard писал(а):Ага, поддерживаю вопрос. что по dhcp серверу?
В предыдущие месяцы было катастрофически мало времени заниматься чем-то кроме обязательных дел и работы. Потому на время проект заглох.
Но сейчас плавненько восстанавливается и в общем-то намечаются некоторые успехи.
Спасибо всем кто выкладывает файлики с 82й опцией - в ближайшее время думаю пригодятся, хотя надеюсь сделать процесс парсинга достаточно универсальным для любой опции.

Кроме того, хочется мягко намекнуть/попросить кое о чём. Отчасти проект временно заглох в связи со сменой мною работы и вида деятельности по сути - теперь я ни как не связан с провайдингом и DHCP в принципе. Как следствие - весьма ощутимо утратилась мотивация развивать софт этого направления. И так, перейду от намёков к сути: "мотивация" в виде $$$ приветствуется и может весьма подогреть мой личный интерес к выпуску данного продукта в готовом виде.
Конечно это не значит что если вдруг все проигнорируют данную просьбу то я на всех обижусь, напишу что-то и буду продавать за деньги с закрытыми исходниками. Нет! Проект в любом случае будет открытый, и я думаю что в любом случае будет.
Просто действительно хотелось бы ощутить если возможно - материальную мотивацию писать хороший код. Ну и конечно отношение к просьбам/пожеланиям тех кто поможет мне будет несколько более тёплым чем к просьбам остальных :-)
Разумеется я не прошу что бы это было прямо сейчас, пока я всех только обещаниями по факту кормлю. Когда будет что показать, PoC так сказать - тогда и будет не лишним.
И так, кому сколько не жалко (если такие найдутся) - озвучте в личку.

Аватара пользователя
TiRider
Сообщения: 568
Зарегистрирован: Сб июн 07, 2008 12:43

Сообщение TiRider »

Собственно интересует вопрос, а накой использовать freeradius? Если у кого то стоит стандартный радиус от нетапа. Может нужно разделить проект и написать релей не для freeradius, а для нетаповского.

MiO
Сообщения: 303
Зарегистрирован: Ср окт 01, 2008 23:34

Сообщение MiO »

да, на нетаповском было бы куда лучше.

Аватара пользователя
TiRider
Сообщения: 568
Зарегистрирован: Сб июн 07, 2008 12:43

Сообщение TiRider »

Понятно дело, что у нетаповцев нет желания писать dhcp-relay, но вот автор (респектище конечно), мог подумать, что не у всех стоит пресловутый freeradius, и как то существующую схему перестраивать нет ни желания, ни времени...

Arti
Сообщения: 266
Зарегистрирован: Пн окт 01, 2007 02:44

Сообщение Arti »

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

Pulse
Сообщения: 945
Зарегистрирован: Вт окт 03, 2006 12:58

Сообщение Pulse »

Arti писал(а):Вы меня конешно извините, но нетаповский радиус годится только для небольших не масштабируемых инсталляций. Так что закладывается на него нет смысла никакого.
оффтопканешна, но как сделать динамические адреса с freeradius?

Arti
Сообщения: 266
Зарегистрирован: Пн окт 01, 2007 02:44

Сообщение Arti »

Так же как это сделано на нетапе - через урфа.

Если уже пошла такая пьянка - то раскажите как Вы будете искать "ip-группы" для DHCP и как это будет сосчитаться с "ip-группами" для доступа в Internet.

Вобще луше не делать зависимостей там, где этого не нужно.

Аватара пользователя
hellard
Сообщения: 52
Зарегистрирован: Вт апр 05, 2005 05:59
Откуда: Абакан
Контактная информация:

Сообщение hellard »

Arti писал(а): 82 опцию можно распарсить так (это длинк, по-хорошему нужно делать боле универсально):
то есть если не длинк, обламываться на ходу?

Arti
Сообщения: 266
Зарегистрирован: Пн окт 01, 2007 02:44

Сообщение Arti »

hellard писал(а):
Arti писал(а): 82 опцию можно распарсить так (это длинк, по-хорошему нужно делать боле универсально):
то есть если не длинк, обламываться на ходу?
Если Вы не заметили, это пример не претендующий на истину в последней инстанции. Сделайте для себя так как это ВАМ нужно.

RomanCh
Сообщения: 20
Зарегистрирован: Вт авг 18, 2009 16:54
Контактная информация:

Сообщение RomanCh »

И так, как по-моему (т.е. в моей реализации) это должно работать. Обращаю внимание что основной целью не является привязка сервера к netup'овскому биллингу и какому-либо оборудованию. Основная цель - возможность прикрутить сервер по возможности к большему числу СУБД с возможностью наиболее универсальной настройки.

В конфиге используется (пока) 3 sql запроса. Для dhcpdiscover, dhcprequest & dhcprelease. Покажу суть на примере первого:

Код: Выделить всё

QueryDiscover = select code, value from dhcp_data where ether = '$CLI-ETHER-ADDR$'
QueryDiscover - название опции конфига. Далее сам запрос. Обязательно в запросе должно быть соблюдено только одно условие - select должен делать выборку по полям code & value именно в таком порядке. Которые соответственно обозначают код DHCP опции и её значение. Разумеется важны не сами названия полей, а суть возвращаемых базой значений.
Откуда будет делаться выборка (из таблицы, view, или какого-нибудь порождения набора данных через union, или вообще что угодно) - совершенно не важно.

Далее рассмотрим секцию where. В принципе в неё можно написать какое угодно условие, удовлетворяющее вашим задачам. Конечно самое интересное - использование переменной $CLI-ETHER-ADDR$. Очевидно что делать фиксированный набор переменных - недальновидно. Потому все необходимые переменные для условия можно описать в конфиге. Пример объявления переменной в конфиге:
Var = CLI-ETHER-ADDR h:28:6 # Ethernet address
По пунктам - Var собственно директива объявления переменной, далее идёт имя переменной используемое как $имя$ в sql запросах. Далее идёт описание формата данных выбираемых из пакета и подставляемых в запрос:
h - значит что переменная берётся из заголовка DHCP сообщения (header) а не из поля опций.
28 - указывает смещение от начала заголовка. На 28м байте начинается client hardware address.
6 - длина опции. Понятно что для ethernet'а это будет 6.

Но, как можно заметить - сделать только такие переменные будет недостаточно, например для решения той же пресловутой проблемы с 82й опцией. Потому переменные из поля "опции" можно получать с различными условиями. Ниже дан пример абсолютно бессмысленный на практике, но показывающий принципы работы таких переменных:

Код: Выделить всё

Var = CLI-NAME			o&#58;60&#58;&#40;0=00&#41;0&#58;2|&#40;5=64726f70706572&#41;5&#58;2|0&#58;0
Объявляется переменная CLI-NAME. Пояснения к формату:
o - обозначает что переменная получается из поля "опции" (options) dhcp запроса.
60 - DHCP обозначает код этой опции (client-name).
Далее идёт набор условий. Каждое условие представляет из себя подобие стандартного тернарного оператора многих языков программирования. Пояснение:
(0=00) - первое условие. Слева от = смещение в байтах от начала значения опции (опции 60 в данном случае). Справа - байтовая последовательность которая сравнивается со значением опции начиная с этого смещения. В данном случае это значит: "если начиная с байта 0 идёт последовательность байт 0x00".
0:2 - выполняется если условие верно. 0 - смещение в байтах от начала значения опции. 2 - сколько байт взять для получения значения переменной.
| - значит то же самое что else в операторе if(...) ... else ...
Далее должна идти либо такая же пара смещение:значение указывающая что нужно вернуть в случае не соблюдения условия, либо - следующий условный оператор. У нас второе.
(5=64726f70706572) - опять условие, читающееся как: "с 5го байта должна идти последовательность байт 0x64726f70706572".
5:2 - взять 2 байта для значения переменной если условие верно
| - else
0:0 - начиная с нулевого смещения взять все байты опции. Если длина равна нулю - возвращаются все байты начиная с байта смещения и заканчивая концом опции. В случае нулевого смещения это значит - все байты опции. Удобно для применения в качестве поведения "по умолчанию".

Другой пример - допустим вам не нужны условия и вы желаете использовать всё значение опции целиком. Тогда объявление переменной будет выглядеть проще:

Код: Выделить всё

Var = CLI-NAME			o&#58;60
Это вернёт в запрос всё значение переменной. В принципе тут так же можно указать смещение:длина и получить строго столько байт, сколько хочется, например: o:60:1:5 - взять 5 байт начиная с 1го из 60й опции.
На всякий случай - значения переменных приходят в запрос в виде строки шестнадцатиричных цифр. Смещение расчитывается начиная с нуля.
Я конечно понимаю что пока конфиг будет немного похож на какой-то "птичий язык" из-за объявлений переменных, но впоследствии, когда будут решены более важные задачи, сделаю встроенные именованные переменные дабы избежать ручного прописывания общеупотребимых опций.

По-моему такой подход должен решить назойливую проблему с распарсиванием 82й опции. Если у кого-то есть мнение почему что-либо может не получиться, и вообще, какие-либо ценные замечания - прошу изложить, и чем раньше тем лучше.
И - есть-ли какие-нибудь принципиальные невозможности стыковки сервера на подобной концепции с тем же netup'ом?

RomanCh
Сообщения: 20
Зарегистрирован: Вт авг 18, 2009 16:54
Контактная информация:

Сообщение RomanCh »

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

Arti
Сообщения: 266
Зарегистрирован: Пн окт 01, 2007 02:44

Сообщение Arti »

RomanCh писал(а):Хм, кажется я сам уже понял чего точно будет не хватать. Нужно реализовать возможность использования внутри условия других переменных - что бы например вычислять длины всяких подопций внутри 82й опции.
В принципе можно поступить так.

Набить "стандартных" параметров - например порт, номер влана, MAC. По большому счёту этого достаточно, идентифицировать сам релей можно по IP с которого пришёл запрос.

В конфиге можно посто указывать смещения влана и порта, а SQL в запрос создаваемый пользователем добавлять соотвественно переменные типа _RELAY_ _PORT_ _VLAN_ _MAC_. Примерно так, как это сделано во FreeRadius.

Хотя конешно на вкус на цвет....

RomanCh
Сообщения: 20
Зарегистрирован: Вт авг 18, 2009 16:54
Контактная информация:

Сообщение RomanCh »

Arti писал(а):В принципе можно поступить так.

Набить "стандартных" параметров - например порт, номер влана, MAC. По большому счёту этого достаточно, идентифицировать сам релей можно по IP с которого пришёл запрос.
Думал о чём-то подобном. Но это помоему несколько напоминает брутфорс :-) Лучше уж изначально сделать более идеологически верно, а там - пусть каждый пишет конфиг как ему удобно.

Ответить