<?xml version="1.0" encoding="UTF-8" ?>

<bugzilla version="5.2"
          urlbase="https://bugzilla.altlinux.org/"
          
          maintainer="jenya@basealt.ru"
>

    <bug>
          <bug_id>51620</bug_id>
          
          <creation_ts>2024-10-02 15:16:07 +0300</creation_ts>
          <short_desc>Ошибка обновления dns записей при наличии нескольких ip адресов на одном интерфейсе</short_desc>
          <delta_ts>2025-08-21 11:15:53 +0300</delta_ts>
          <reporter_accessible>1</reporter_accessible>
          <cclist_accessible>1</cclist_accessible>
          <classification_id>4</classification_id>
          <classification>Development</classification>
          <product>Sisyphus</product>
          <component>samba-winbind-dnsupdate</component>
          <version>unstable</version>
          <rep_platform>x86_64</rep_platform>
          <op_sys>Linux</op_sys>
          <bug_status>NEW</bug_status>
          <resolution></resolution>
          
          <see_also>https://bugzilla.altlinux.org/show_bug.cgi?id=55600</see_also>
          <bug_file_loc></bug_file_loc>
          <status_whiteboard></status_whiteboard>
          <keywords></keywords>
          <priority>P5</priority>
          <bug_severity>normal</bug_severity>
          <target_milestone>---</target_milestone>
          
          
          <everconfirmed>1</everconfirmed>
          <reporter name="Nikolai Zurabishvili">zurabishvilinn</reporter>
          <assigned_to name="Evgenii Sozonov">arzdez</assigned_to>
          <cc>arseny</cc>
    
    <cc>liannnix</cc>
    
    <cc>sin</cc>
    
    <cc>varaksaaa</cc>
          
          <qa_contact>qa-sisyphus</qa_contact>

      

      

      

          <comment_sort_order>oldest_to_newest</comment_sort_order>  
          <long_desc isprivate="0" >
    <commentid>252456</commentid>
    <comment_count>0</comment_count>
    <who name="Nikolai Zurabishvili">zurabishvilinn</who>
    <bug_when>2024-10-02 15:16:07 +0300</bug_when>
    <thetext>samba-winbind-dnsupdate-0.5-alt2

Стенды (обновлены до сизифа):

Workstation 10.2 x86-64 - клиент
Server 10.2 office x86-64 - dc

Предусловия: Развернут Samba домен, клиенты введены в домен. На клиенте имеется несколько ip адресов на одном интерфейсе:
# ip a
...
2: eth0: &lt;BROADCAST,MULTICAST,UP,LOWER_UP&gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000
    ...
    inet &lt;ipv4-1&gt; brd &lt;brd-adr&gt; scope global dynamic noprefixroute eth0
       valid_lft 1320sec preferred_lft 1320sec
    inet &lt;ipv4-2&gt; scope global secondary eth0
       valid_lft forever preferred_lft forever
    inet6 &lt;ipv6-1&gt; scope global dynamic mngtmpaddr proto kernel_ra 
       valid_lft 86393sec preferred_lft 14393sec
    inet6 &lt;ipv6-2&gt; scope link proto kernel_ll 
       valid_lft forever preferred_lft forever

Шаги (выполнять на клиенте):
1. # winbind-dnsupdate или # winbind-dnsupdate --disable-dconf -6 (для ipv6) 

Ожидаемый результат: Корректное обновление dns записей для dc

Фактический результат: Ошибка обновление dns записей :

[INFO]: Current IPv4 address: &lt;ipv4-1&gt;
&lt;ipv4-2&gt;
[INFO]: IPv4 address in DNS server: &lt;dc-ipv4&gt;
[INFO]: The IPv4 address of interface eth0 has been changed.
[INFO]: Start the A record update.
[ERROR]: Nsupdate error:
[ERROR]: incorrect section name: &lt;ipv4-2&gt;
syntax error
[ERROR]: A record update failed.

(Для ipv6) :

[INFO]: Current IPv6 address: &lt;ipv6-1&gt;
&lt;ipv6-2&gt;
[INFO]: IPv6 address in DNS server: &lt;dc-ipv6&gt;
[INFO]: The IPv6 address of interface eth0 has been changed.
[INFO]: Start the AAAA record update.
[ERROR]: Nsupdate error:
[ERROR]: incorrect section name: &lt;ipv6-2&gt;
syntax error
[ERROR]: A record update failed.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>270920</commentid>
    <comment_count>1</comment_count>
    <who name="Arseny Maslennikov">arseny</who>
    <bug_when>2025-08-14 18:36:53 +0300</bug_when>
    <thetext>https://git.altlinux.org/gears/s/..git?p=samba-winbind-dnsupdate.git;a=blob;f=winbind-dnsupdate;hb=0.7.1-alt1

На строках 585 и 608 глючные функции; они при наличии нескольких адресов на интерфейсе дампят их все через LF. А потом validate_ipv{4,6} ничего по факту не валидируют.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>270921</commentid>
    <comment_count>2</comment_count>
    <who name="Arseny Maslennikov">arseny</who>
    <bug_when>2025-08-14 18:37:08 +0300</bug_when>
    <thetext>
Далее рекомендации тем, кто будет фиксить:
1) Не надо парсить обычный вывод `ip(8)`. Легко ошибиться, легко словить регрессию. Варианты:
  * ip -br a ...
  * ip -j a ...
Если возьмёте последний, лучше покройте его тестами своими; апстрим iproute2 системно таким не занимается, там бывают регрессии и не все команды умеют выдавать json-данные. Апстрим будет рад, конечно, увидеть патчи.
2) Не надо регулярками парсить текстовое представление адреса, это смерть. IPv6 в этом плане, кстати, проще, чем IPv4. Нужно применить алгоритм inet_pton(3), что на шелле нелегко. Правда, поговорить с ядром по RTNL и получить оттуда адреса в бинарном network byte order виде ещё сложнее.
3) Не надо хавать какие попало адреса.
Понятно, что ряд адресов выпадают из множ-ва тех, которые имеет смысл регистрировать в домене. Этот ряд — подмножество вот этих двух списков:
https://www.iana.org/assignments/iana-ipv6-special-registry/iana-ipv6-special-registry.xhtml
https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml
* Локалхост (::1/128, 127.0.0.0/8)
* IPv4-mapped IPv6 (::ffff:0:0/96)
* Link-local (fe80::/10, 169.254.0.0/16)
* 6to4 (2002::/16)
* ...
Вот это и нужно валидировать. IPv4-mapped и link-local надо обязательно отрывать. Скрыть link-local можно, передав ip(8) фильтр `scope global`.

Кроме того, для IPv6 нужна политика, какие адреса предпочтительно там регистрировать, здесь нужен экспертный совет по домен-решению. Primary/non-temporary или secondary/temporary? Если temporary, то надо брать valid и preferred lifetime в рассмотрение (подозреваю, что и для IPv4 DHCP-клиент их выставляет). В любом случае надо протухшие адреса убирать.
Вот так выглядит результат в неплохом приближении:
  # ip -br -f $family addr show scope global -tentative -deprecated
Но тут всё равно адресов может оказаться несколько, PTR для них всех нужно прописывать. Что приводит нас к пункту 4...</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>270922</commentid>
    <comment_count>3</comment_count>
    <who name="Arseny Maslennikov">arseny</who>
    <bug_when>2025-08-14 18:38:17 +0300</bug_when>
    <thetext>4) Не должна ли эта программа быть даймоном и реагировать на события, например, от `ip monitor`? Адрес появился (add), у адреса изменились флаги либо другое состояние (он по-change-ился), адрес пропал (delete).
Или не быть даймоном, а запускаться этим даймоном по событию (fork-exec на событие, конечно, но хоть что-то).

Может быть, уже так и есть, а я не в курсе; тогда хорошо.</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>271171</commentid>
    <comment_count>4</comment_count>
    <who name="Artem Varaksa">varaksaaa</who>
    <bug_when>2025-08-21 10:36:06 +0300</bug_when>
    <thetext>(Ответ для Arseny Maslennikov на комментарий #3)
&gt; 4) Не должна ли эта программа быть даймоном и реагировать на события,
&gt; например, от `ip monitor`? Адрес появился (add), у адреса изменились флаги
&gt; либо другое состояние (он по-change-ился), адрес пропал (delete).
&gt; Или не быть даймоном, а запускаться этим даймоном по событию (fork-exec на
&gt; событие, конечно, но хоть что-то).
&gt; 
&gt; Может быть, уже так и есть, а я не в курсе; тогда хорошо.

В samba-winbind-dnsupdate-0.7.1-alt1.noarch есть .service и .timer:

/usr/lib/systemd/system/winbind-dnsupdate.service
/usr/lib/systemd/system/winbind-dnsupdate.timer


# /usr/lib/systemd/system/winbind-dnsupdate.service
[Unit]
Description=Update dns record service
After=network.target network-online.target

[Service]
Type=oneshot
EnvironmentFile=-/etc/sysconfig/winbind-dnsupdate
ExecStart=/usr/bin/winbind-dnsupdate $OPTIONS

[Install]
WantedBy=multi-user.targe


# /usr/lib/systemd/system/winbind-dnsupdate.timer
[Unit]
Description=Update dns record Daily and on boot

[Timer]
OnBootSec=5min
OnUnitActiveSec=60min

[Install]
WantedBy=timers.target</thetext>
  </long_desc><long_desc isprivate="0" >
    <commentid>271177</commentid>
    <comment_count>5</comment_count>
    <who name="Arseny Maslennikov">arseny</who>
    <bug_when>2025-08-21 11:15:53 +0300</bug_when>
    <thetext>(In reply to Artem Varaksa from comment #4)
&gt; (Ответ для Arseny Maslennikov на комментарий #3)
&gt; &gt; 4) Не должна ли эта программа быть даймоном и реагировать на события,
&gt; &gt; например, от `ip monitor`? Адрес появился (add), у адреса изменились флаги
&gt; &gt; либо другое состояние (он по-change-ился), адрес пропал (delete).
&gt; &gt; Или не быть даймоном, а запускаться этим даймоном по событию (fork-exec на
&gt; &gt; событие, конечно, но хоть что-то).
&gt; &gt; 
&gt; &gt; Может быть, уже так и есть, а я не в курсе; тогда хорошо.
&gt; 
&gt; В samba-winbind-dnsupdate-0.7.1-alt1.noarch есть .service и .timer:
&gt; 
&gt; /usr/lib/systemd/system/winbind-dnsupdate.service
&gt; /usr/lib/systemd/system/winbind-dnsupdate.timer
Благодарю за инфо. :)

&gt; # /usr/lib/systemd/system/winbind-dnsupdate.service
&gt; &lt;...&gt;
&gt; 
&gt; # /usr/lib/systemd/system/winbind-dnsupdate.timer
&gt; [Unit]
&gt; Description=Update dns record Daily and on boot
&gt; 
&gt; [Timer]
&gt; OnBootSec=5min
&gt; OnUnitActiveSec=60min
&gt; 
&gt; [Install]
&gt; WantedBy=timers.target
Обновление раз в 60 минут — это, если честно, паллиатив. Оно должно срабатывать по событию изменения множества адресов на интерфейсе (и у главного конкурента, чудаков на букву М, именно так), потому что такое изменение — это преждевременно протухшие записи.

Но просто изменить в таймере промежуток или привязать её к выхлопу `ip monitor addr` — тоже не то, потому что:
— программа, видимо, при работе ещё и выясняет, где сервер, на который слать nsupdate; это несколько DNS-запросов с зависимостью по данным;
— из-за этого слишком часто (в случае флапа адресов на интерфейсе, последовательности мгновенных появлений-пропаданий) её дёргать нельзя, нужен grace period, я бы предложил сделать его сравнимым с neighbour reachability timer, по умолчанию 1,5 секунды.
https://datatracker.ietf.org/doc/html/rfc4861#section-6.3.2, &quot;ReachableTime&quot;</thetext>
  </long_desc>
      
      

    </bug>

</bugzilla>