LINUX.ORG.RU

snat --persistent вычисление src_ip в новых ядрах

 ,


0

1

Есть правило iptables -t nat -A POSTROUTING -j SNAT --to-source 10.1.2.1-10.1.2.255 --persistent

В ядре 2.6.32 код отвечающий за то каким будет src_ip после ната выглядит так: net/ipv4/netfilter/nf_nat_core.c

	/* Hashing source and destination IPs gives a fairly even
	 * spread in practice (if there are a small number of IPs
	 * involved, there usually aren't that many connections
	 * anyway).  The consistency means that servers see the same
	 * client coming from the same IP (some Internet Banking sites
	 * like this), even across reboots. */
	minip = ntohl(range->min_ip);
	maxip = ntohl(range->max_ip);
	j = jhash_2words((__force u32)tuple->src.u3.ip,
			 range->flags & IP_NAT_RANGE_PERSISTENT ?
				0 : (__force u32)tuple->dst.u3.ip, 0);
	j = ((u64)j * (maxip - minip + 1)) >> 32;
	*var_ipp = htonl(minip + j);

для вычисления src_ip после ната использовал такую программу:

#include <stdio.h>
#include <stdint.h>

typedef uint8_t  u8;
typedef uint32_t u32;
typedef uint64_t u64;
#define JHASH_INITVAL           0xdeadbeef

u32 parseIp(char *ipStr)
{
        int i1, i2, i3, i4;
        sscanf(ipStr, "%d.%d.%d.%d", &i1, &i2, &i3, &i4);
        return (i1 << 24) + (i2 << 16) + (i3 << 8) + i4;
}

u32 rparseIp(char *ipStr)
{
        int i1, i2, i3, i4;
        sscanf(ipStr, "%d.%d.%d.%d", &i1, &i2, &i3, &i4);
        return (i4 << 24) + (i3 << 16) + (i2 << 8) + i1;
}

static inline u32 rol32(u32 word, unsigned int shift)
{
        return (word << shift) | (word >> (32 - shift));
}

static inline u32 jhash_2words(u32 a, u32 b, u32 c)
{
        a += JHASH_INITVAL;
        b += JHASH_INITVAL;
        c ^= b; c -= rol32(b, 14);
        a ^= c; a -= rol32(c, 11);
        b ^= a; b -= rol32(a, 25);
        c ^= b; c -= rol32(b, 16);
        a ^= c; a -= rol32(c, 4);
        b ^= a; b -= rol32(a, 14);
        c ^= b; c -= rol32(b, 24);
        return c;
}

int main(int argc, char *argv[]) {
        if (argc < 4) {
                printf("fail");
        }
        u32 minip, maxip, srcip, j, result;
        minip = parseIp(argv[1]);
        maxip = parseIp(argv[2]);
        srcip = rparseIp(argv[3]);
        j = jhash_2words(srcip, 0, 0);
        j = ((u64)j * (maxip - minip + 1)) >> 32;
        result = minip + j;
        printf("%d.%d.%d.%d\n", (u8)(result >> 24), (u8)(result >> 16), (u8)(result >> 8), (u8)result);
        return 0;
}

на вход которой передавал начало диапазона, конец диапазона, приватный ip. На выходе получался публичный адрес который будет после ната. для новых ядер она выдаёт не верный адрес, так как код ядра изменился и выглядит теперь так net/netfilter/nf_nat_core.c:

	/* Hashing source and destination IPs gives a fairly even
	 * spread in practice (if there are a small number of IPs
	 * involved, there usually aren't that many connections
	 * anyway).  The consistency means that servers see the same
	 * client coming from the same IP (some Internet Banking sites
	 * like this), even across reboots.
	 */
	j = jhash2((u32 *)&tuple->src.u3, sizeof(tuple->src.u3) / sizeof(u32),
		   range->flags & NF_NAT_RANGE_PERSISTENT ?
			0 : (__force u32)tuple->dst.u3.all[max] ^ zone);

	full_range = false;
	for (i = 0; i <= max; i++) {
		/* If first bytes of the address are at the maximum, use the
		 * distance. Otherwise use the full range.
		 */
		if (!full_range) {
			minip = ntohl((__force __be32)range->min_addr.all[i]);
			maxip = ntohl((__force __be32)range->max_addr.all[i]);
			dist  = maxip - minip + 1;
		} else {
			minip = 0;
			dist  = ~0;
		}

		var_ipp->all[i] = (__force __u32)
			htonl(minip + (((u64)j * dist) >> 32));
		if (var_ipp->all[i] != range->max_addr.all[i])
			full_range = true;

		if (!(range->flags & NF_NAT_RANGE_PERSISTENT))
			j ^= (__force u32)tuple->dst.u3.all[i];
	}

раньше, как я понял, хеш вычислялся на основе ip адреса (__force u32)tuple->src.u3.ip теперь он вычисляется из (u32 *)&tuple->src.u3 Что это такое я понять не могу. Исходники 2.6.32 и 3.13 скачал, сравнивал, но так и не смог разобраться что к чему. Прошу помочь, разработчиком на С не являюсь.

разработчиком на С не являюсь.

Тогда зачем ты пишешь программы на Си?

anonymous ()
	if (nf_ct_l3num(ct) == NFPROTO_IPV4)
		max = sizeof(var_ipp->ip) / sizeof(u32) - 1;
	else
		max = sizeof(var_ipp->ip6) / sizeof(u32) - 1;

Правильно ли я понимаю что

1.выражение range->flags & NF_NAT_RANGE_PERSISTENT ? 0 : (__force u32)tuple->dst.u3.all[max] ^ zone равно 0 при установленном флаге --persistent

2.цикл for нужен только в случае использования ipv6, а в моём случае max = 0

тогда код будет выглядеть так

j = jhash2((u32 *)&tuple->src.u3, sizeof(tuple->src.u3) / sizeof(u32),0);
minip = ntohl((__force __be32)range->min_addr.all[0]);
maxip = ntohl((__force __be32)range->max_addr.all[0]);
dist  = maxip - minip + 1;

var_ipp->all[0] = (__force __u32) htonl(minip + (((u64)j * dist) >> 32));

и остаётся понять чем отличается (u32 *)&tuple->src.u3 от (__force u32)tuple->src.u3.ip?

tsuser ()
Ответ на: комментарий от anonymous

Надеюсь до написания программ не дойдёт. Исправление пары строк не в счёт.

tsuser ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.