93
Píšete, že příchozí pakety vidíte na správném síťovém rozhraní v tcpdumpu. Ten síťovku uvede hardwarově do promiskuitního režimu a tuším otvírá raw socket (nebo má nějaký háček na ten způsob).
Pokud příchozí paket nevybublá v bindnutém socketu, pátrejte dál, kde se asi tak mohl cestou ztratit.
Cestou = softwarovým stackem vzhůru, protože z hardwaru do kernelu jste ho už dostal.
Příchozí cílová MAC adresa sedí? Pokud ano, driver stack nemá důvod paket zahodit na základě toho, že přišel s nesprávnou cílovou MAC adresou.
Když pogooglíte SO_BINDTODEVICE, najdete historické zmínky od lidí, že to použili a že jim to fungovalo. Najdeta taky zmínku starou snad 20 let, že SO_BINDTODEVICE je nějaká deprecated dočasná obezlička - ale i následné reakce, že to je pitomost, když se to v upstreamu drží dodnes naživu.
Potkal jsem taky zmínku od konkrétního člověka, kterému to nejelo - a vyskytla se tam rada někoho dalšího, zkusit vypnout rp_filter (já na to přišel vlastní úvahou).
rp_filter tradičně zahazuje podle zdrojové IP adresy pakety, které přišly z rozhraní, kam nevede route s odpovídajícím cílem. Klasické použití je například u strojů, které mají dvě upstream rozhraní do divokého internetu ke dvěma ISP, default route vede jedním z nich, ale chcete brát příchozí provoz i druhým uplinkem (a dál si už nějak zařídíte stateful routing odpovědí = to už je jiná pohádka, zde OT).
Vaše situace je jiná. Vy máte více rozhraní do téhož L2 subnetu. Holý Linux se v takové situaci tradičně chová tak, že jako odchozí rozhraní používá tvrdošíjně stále jedno. Dokonce snad i v případě, kdy je na dotyčném fyzickém portu L1 link down (pak to nefunguje vůbec). Proto takové konfigurace běžně nepoužívám a nemám s nimi zkušenosti. Čekal bych, že "locally connected" route pro daný subnet uvidím ve směrovací tabulce třikrát (pro tři fyzická rozhraní, číslovaná z téhož subnetu). Viz příkaz "route" (bez argumentů). Pokud ho vidíte jenom jednou, máte o důvod víc, mračit se na rp_filter. Ale i pokud ten route vidíte třikrát, tak standardní chování je, že reálně funguje jenom ten první. Neznám detaily fungování rp_filtru pod kapotou / na úrovni zdrojáků jádra, abych řekl, zda může za Váš problém.
Jak to prakticky vyzkoušet:
Globální vypnutí rp_filteru:
echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
Vypnout rp_filter pro jedno konkrétní rozhraní (mělo by přestat dropovat nevyhovující pakety):
echo 0 > /proc/sys/net/ipv4/conf/enp0s8/rp_filter
Pokud to zabere, tak natrvalo to zadáte jedním z několika způsobů:
- /etc/rc.local
- /etc/sysctl.conf (lze editovat ručně, nebo utilitou sysctl z příkazového řádku)
- příslušný ifup skript, nebo ekvivalent pro Váš způsob správy síťových rozhraní...
- konfigurace firewallu
- ...
Pokud se rp_filter ukáže jako falešná stopa, tak se pro jistotu podívejte, jak vypadá konfigurace IPtables:
iptables -L
iptables -t nat -L
A tady moje vědomosti "od stolu" zhruba končí. Následovalo by asi nějaké bádání ve vnitřnostech routovacího stacku, asi by tam šlo něco trasovat i bez zkoumání zdrojáků apod.