FreeBSD. Патч mpd5 для NAT редиректа портов .

С появлением второго сервера в домашнем кластере =) потребовалось перебросит на него порты из вне. Так как подключением и трансляцией адресов(NAT) занимается mpd5, то пришлось в очередной раз изучать мануалы по нему. Изначально mpd поднималась по старым конфигам версии 5.4, которая не умела перенаправлять порты через NAT, но в версии 5.4 одним из новшеств было как раз - Add NAT redirections support. Что необходимо сделать: перекинуть порт 8081 из внешней сети(интернет) в локальную на сервер с адресом 192.168.0.2. И так приступаем...

Имеем сервер на FreeBSD 8.1 с GENERIC ядром:

bsd# uname -v
FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:36:49 UTC 2010     root@mason.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC 

Грабли mpd версии 5.5.

В кратце опишу по каким граблям пришлось пройти при настройке NAT redirections в mpd версии 5.5.

Согласно мануалу был исправлен mpd.conf:

startup:
set user %mpd_username% %mpd_password% admin
set console self %mpd_console_address% %mpd_console_port%
set console open
set web self %mpd_web_address% %mpd_web_port%
set web open
set link enable report-mac

default:
load l2tp_client

 create link static L1 pptp
 set link action bundle B1
 set link accept chap
 set auth authname %beeline_username%
 set auth password %beeline_password%
 set link max-redial 0
 set link latency 0
 set link mtu 1460
 set link keep-alive 60 180
 set pptp peer vpn.internet.beeline.ru
 open

l2tp_client:

 create bundle static B1
 set iface enable nat
 set nat red-port tcp 0.0.0.0 8081 192.168.0.2 8081
 set iface enable tcpmssfix
 set iface up-script /usr/local/etc/mpd5/ng0-up.sh
 set iface down-script /usr/local/etc/mpd5/ng0-down.sh
 set ipcp ranges 0.0.0.0/0 0.0.0.0/0
 set ipcp no vjcomp
 
 create link static L1 l2tp
 set link action bundle B1
 set link accept chap
 set auth authname %beeline_username%
 set auth password %beeline_password%
 set link max-redial 0
 set link latency 0
 set link mtu 1460
 set link keep-alive 60 180
 set l2tp peer tp.internet.beeline.ru
 open

После перезапуска mpd, порт извне остался не доступен:

# /usr/local/etc/rc.d/mpd5 restart

Посмотрев созданную в netgraph ноду nat, был приятно удивлен:

# ngctl msg mpd`cat /var/run/mpd5.pid`-B1-nat: listredirects
Rec'd response "listredirects" (10) from "[9d]:":
Args: { total_count=1 redirects=[ { id=1 local_addr=192.168.0.2 local_port=37151 alias_port=37151 proto=6 description="nat-port-0" } ] }

Странная конвертация значения 8081 в 37151 удивила. Гугл рассказал мне, что удивлен был не только я =) Причем, если в mpd.conf прописать 37151, то получим необходимый редирект на порт 8081:

# set nat red-port tcp 0.0.0.0 8081 192.168.0.2 8081
 set nat red-port tcp 0.0.0.0 37151 192.168.0.2 37151
# ngctl msg mpd`cat /var/run/mpd5.pid`-B1-nat: listredirects
Rec'd response "listredirects" (10) from "[9d]:":
Args: { total_count=1 redirects=[ { id=1 local_addr=192.168.0.2 local_port=8081 alias_port=8081 proto=6 description="nat-port-0" } ] }

В принципе можно было оставит все как есть, но любовь к порядку взяла верх и изыскания продолжились. Оказалось, что числовое значение конвертируется из узлового в сетевой порядок расположения байтов функцией htons. А ng_nat ожидает номер порта в узловом порядке, т.е. без преобразования. Дальнейшие изыскания в очередной раз подтвердили не оперативность обновления дерева портов FreeBSD, т.к. версия 5.5. была выпущена 16.02.2010, добавлена в порты 25.02.2010 и 26.04.2010 была исправлена ошибка в svn mpd, однако порт не обновлен даже на предмет патчей. Придется патчить самостоятельно.

Патчим mpd версии 5.5.

Идем на http://mpd.cvs.sourceforge.net/ и смотрим текущую версию файла nat.c. На момент написания статьи версия была 1.13, так же смотрим версию файла на момент релиза 5.5 которым является версия 1.10. Далее формируем адресную строку для получения патча между версиями файла:

http://mpd.cvs.sourceforge.net/viewvc/mpd/mpd/src/nat.c?r1=1.10&r2=1.13&view=patch

Где параметр r1 - ранняя версия, r2 - текущая. Переходим в каталог /tmp скачиваем файл в /tmp/patch-nat.c, ссылку обязательно помещаем в кавычки:

# fetch -o patch-nat.c "http://mpd.cvs.sourceforge.net/viewvc/mpd/mpd/src/nat.c?r1=1.10&r2=1.13&view=patch"fetch: http://mpd.cvs.sourceforge.net/viewvc/mpd/mpd/src/nat.c?r1=1.10&r2=1.13&view=patch: size of remote file is not known
patch-nat.c                                             3507  B 8989 kBps

Получили следующий файл:

--- nat.c 2010/02/16 18:47:34 1.10
+++ nat.c 2010/04/26 15:22:54 1.13
@@ -35,19 +35,21 @@
 
   const struct cmdtab NatSetCmds[] = {
     { "address {addr}",  "Set alias address",
- NatSetCommand, NULL, 2, (void *) SET_ADDR },
+ NatSetCommand, AdmitBund, 2, (void *) SET_ADDR },
     { "target {addr}",  "Set target address",
- NatSetCommand, NULL, 2, (void *) SET_TARGET },
+ NatSetCommand, AdmitBund, 2, (void *) SET_TARGET },
+#ifdef NG_NAT_DESC_LENGTH
     { "red-port {proto} {alias_addr} {alias_port} {local_addr} {local_port} [{remote_addr} {remote_port}]", "Redirect port",
- NatSetCommand, NULL, 2, (void *) SET_REDIRECT_PORT },
+ NatSetCommand, AdmitBund, 2, (void *) SET_REDIRECT_PORT },
     { "red-addr {alias_addr} {local_addr}", "Redirect address",
- NatSetCommand, NULL, 2, (void *) SET_REDIRECT_ADDR },
+ NatSetCommand, AdmitBund, 2, (void *) SET_REDIRECT_ADDR },
     { "red-proto {proto} {alias-addr} {local_addr} [{remote-addr}]", "Redirect protocol",
- NatSetCommand, NULL, 2, (void *) SET_REDIRECT_PROTO },
+ NatSetCommand, AdmitBund, 2, (void *) SET_REDIRECT_PROTO },
+#endif
     { "enable [opt ...]",  "Enable option",
- NatSetCommand, NULL, 2, (void *) SET_ENABLE },
+ NatSetCommand, AdmitBund, 2, (void *) SET_ENABLE },
     { "disable [opt ...]",  "Disable option",
- NatSetCommand, NULL, 2, (void *) SET_DISABLE },
+ NatSetCommand, AdmitBund, 2, (void *) SET_DISABLE },
     { NULL },
   };
 
@@ -79,12 +81,14 @@
   Enable(&nat->options, NAT_CONF_INCOMING);
   Enable(&nat->options, NAT_CONF_SAME_PORTS);
   Disable(&nat->options, NAT_CONF_UNREG_ONLY);
+#ifdef NG_NAT_DESC_LENGTH
   bzero(nat->nrpt, sizeof(nat->nrpt));
   bzero(nat->nrpt_id, sizeof(nat->nrpt_id));
   bzero(nat->nrad, sizeof(nat->nrad));
   bzero(nat->nrad_id, sizeof(nat->nrad_id));
   bzero(nat->nrpr, sizeof(nat->nrpr));
   bzero(nat->nrpr_id, sizeof(nat->nrpr_id));
+#endif
 }
 
 
@@ -124,11 +128,12 @@
       }
       break;
 
+#ifdef NG_NAT_DESC_LENGTH
     case SET_REDIRECT_PORT:
       {
  struct protoent *proto;
  struct in_addr l_addr, a_addr, r_addr;
- int lp, ap, rp, k;
+ int lp, ap, rp = 0, k;
 
  /* Parse */
  if (ac != 5 && ac != 7)
@@ -157,11 +162,11 @@
    if (nat->nrpt_id[k] == 0) {
      memcpy(&nat->nrpt[k].local_addr, &l_addr, sizeof(struct in_addr));
      memcpy(&nat->nrpt[k].alias_addr, &a_addr, sizeof(struct in_addr));
-     nat->nrpt[k].local_port = htons(lp);
-     nat->nrpt[k].alias_port = htons(ap);
+     nat->nrpt[k].local_port = lp;
+     nat->nrpt[k].alias_port = ap;
      if (ac == 7) {
        memcpy(&nat->nrpt[k].remote_addr, &r_addr, sizeof(struct in_addr));
-       nat->nrpt[k].remote_port = htons(rp);
+       nat->nrpt[k].remote_port = rp;
      }
      nat->nrpt[k].proto = (uint8_t)proto->p_proto;
      snprintf(nat->nrpt[k].description, NG_NAT_DESC_LENGTH, "nat-port-%d", k);
@@ -239,6 +244,7 @@
    Error("max number of redirect-proto \"%d\" reached", NM_PROTO);
       }
       break;
+#endif
 
     case SET_ENABLE:
       EnableCommand(ac, av, &nat->options, gConfList);
@@ -270,6 +276,7 @@
  u_addrtoa(&nat->alias_addr,buf,sizeof(buf)));
     Printf("\tTarget addresses: %s\r\n", 
  u_addrtoa(&nat->target_addr,buf,sizeof(buf)));
+#ifdef NG_NAT_DESC_LENGTH
     Printf("Redirect ports:\r\n");
     for (k=0;knrpt_id[k]) {
@@ -305,6 +312,7 @@
  Printf("\t%s %s %s %s\r\n", proto->p_name, ai, li, ri);
       }
     }
+#endif
     Printf("NAT options:\r\n");
     OptStat(ctx, &nat->options, gConfList);
     return(0);

Правим первые строки полученного файла, точнее добавляем ему путь к расположению файла nat.c:

на

--- src/nat.c 2010/02/16 18:47:34 1.10
+++ src/nat.c 2010/04/26 15:22:54 1.13

И одновременно копируем наш патч в файл /usr/ports/net/mpd5/patch-nat.c командой:

# cat patch-nat.c | sed s:nat.c:src/nat.c: > /usr/ports/net/mpd5/patch-nat.c

Переходим в каталог /usr/ports/net/mpd5 удаляем, чистим, патчим и устанавливаем порт:

# make deinstall clean
===>  Deinstalling for net/mpd5
===>   Deinstalling mpd-5.5
===>  Cleaning for mpd-5.5
# make patch
===>  Vulnerability check disabled, database not found
===>  License check disabled, port has not defined LICENSE
===>  Found saved configuration for mpd-5.5
===>  Extracting for mpd-5.5
=> SHA256 Checksum OK for mpd5/mpd-5.5.tar.gz.
===>  Patching for mpd-5.5
===>  Applying FreeBSD patches for mpd-5.5
# make install clean
===>   mpd-5.5 depends on shared library: pdel.0 - found
===>  Configuring for mpd-5.5
...
===>  Cleaning for mpd-5.5

Правим настройки mpd.conf перебрасываемых портов на привычные числовые 8081 и перезапускаем mpd:

# /usr/local/etc/rc.d/mpd5 restart

Проверяем редирект в netgraph:

# ngctl msg mpd`cat /var/run/mpd5.pid`-B1-nat: listredirects
Rec'd response "listredirects" (10) from "[9d]:":
Args: { total_count=1 redirects=[ { id=1 local_addr=192.168.0.2 local_port=8081 alias_port=8081 proto=6 description="nat-port-0" } ] }

Пользуем локальный ресурс из внешней сети ) Только при обновлении портов наш патч удалится из порта, но думаю пересобирать порт до выхода следующей версии mpd не прийдется, а в ней уже будет исправлена данная ошибка.

1 комментарий:

Анонимно комментирует...

These files should be stored in PATCHDIR (usually files/, from where they will be automatically applied. All patches must be relative to WRKSRC (generally the directory your port's tarball unpacks itself into, that being where the build is done).
Следовательно класть в
/usr/ports/net/mpd5/files/patch-nat.c