Python Protobuf (адрес IPv4 / IPv6) в Clickhouse FixedString (16) - PullRequest
0 голосов
/ 05 августа 2020

Использование простого определения protobuf, например:

syntax = "proto3";

package flowprotobuf;

message FlowMessage {
    bytes SourceIP = 6;
    bytes DestIP = 7;
}

Как правильно кодировать адрес IPv4 / IPv6, чтобы вставить его в таблицу Clickhouse с типами FixedString(16), установленными для обоих SourceIP и DestIP?

После нескольких дней езды на автобусе борьбы я в настоящее время делаю следующее (Python 3), чтобы выгрузить поток protobuf в топи c Kafka (а затем потреблять через Clickhouse Kafka engine и материализованное представление) с "хорошим" результатом:

#!/usr/bin/env python

import flow_pb2
from google.protobuf.internal.encoder import _VarintBytes
from socket import inet_pton, AF_INET, AF_INET6
from binascii import hexlify

def pack_addr(ipaddr):
    if ':' in ipaddr:
        l = int(hexlify(inet_pton(AF_INET6, ipaddr)), 16)
        return l.to_bytes(16, byteorder='big')
    else:
        l = int(hexlify(inet_pton(AF_INET, ipaddr)), 16)
        return l.to_bytes(16, byteorder='big')

fm = flow_pb2.FlowMessage()
fm.SourceIP = pack_addr(ip_src)
fm.DestIP = pack_addr(ip_dst)

size = fm.ByteSize()
fpb = _VarintBytes(size) + fm.SerializeToString()

producer.produce(kafka_producer_topic, fpb)
producer.poll(0)

Я заключил хорошее в кавычки, потому что согласно документации Clickhouse для IPv6NumToString():

Принимает значение FixedString (16), содержащее адрес IPv6 в двоичном формате. Возвращает строку, содержащую этот адрес в текстовом формате. Отображенные IPv6-адреса IPv4 выводятся в формате :: ffff: 111.222.33.44.

Однако мои результаты запроса не показывают формат ::ffff:x.x.x.x - вместо этого:

de33137dfc80 :) SELECT Date,TimeReceived,IPv6NumToString(SourceIP),IPv6NumToString(DestIP) FROM test LIMIT 5;

SELECT
    Date,
    TimeReceived,
    IPv6NumToString(SourceIP),
    IPv6NumToString(DestIP)
FROM test
LIMIT 5

┌───────Date─┬────────TimeReceived─┬─IPv6NumToString(SourceIP)─┬─IPv6NumToString(DestIP)─┐
│ 2020-08-05 │ 2020-08-05 06:41:27 │ ::98.158.157.211          │ ::202.122.147.98        │
│ 2020-08-05 │ 2020-08-05 06:41:27 │ ::98.158.157.211          │ ::217.118.23.125        │
│ 2020-08-05 │ 2020-08-05 06:41:27 │ ::192.34.21.69            │ ::104.34.73.41          │
│ 2020-08-05 │ 2020-08-05 06:41:27 │ ::98.158.157.211          │ ::194.28.167.103        │
│ 2020-08-05 │ 2020-08-05 06:41:27 │ ::98.158.148.89           │ ::79.170.71.49          │
└────────────┴─────────────────────┴───────────────────────────┴─────────────────────────┘

5 rows in set. Elapsed: 0.006 sec.

Я знаю, что адреса IPv4 верны, и он также правильно отображает адреса IPv6. Я просто хочу убедиться, что не упускаю ничего вопиющего / очевидного. Спасибо.

Отредактировано для добавления: Clickhouse server version 20.5.4 revision 54435

EDIT 2: Предложение Дениса, приведенное ниже, привело меня к решению:

    else:
        m = '::ffff:' + ipaddr
        l = int(hexlify(inet_pton(AF_INET6, m)), 16)
        return l.to_bytes(16, byteorder='big')

1 Ответ

1 голос
/ 05 августа 2020
SELECT hex(IPv6StringToNum('::98.158.157.211'))

┌─hex(IPv6StringToNum('::98.158.157.211'))─┐
│ 000000000000000000000000629E9DD3         │
└──────────────────────────────────────────┘

SELECT hex(IPv6StringToNum('::ffff:98.158.157.211'))

┌─hex(IPv6StringToNum('::ffff:98.158.157.211'))─┐
│ 00000000000000000000FFFF629E9DD3              │
└───────────────────────────────────────────────┘

https://en.wikipedia.org/wiki/IPv6_address Например, сопоставленный IPv4-адрес IPv6 :: ffff: c000: 0280 записывается как :: ffff: 192.0.2.128, таким образом четко выражая исходный текст. IPv4-адрес, сопоставленный с IPv6

https://www.ultratools.com/tools/ipv4toipv6 0: 0: 0: 0: 0: ffff: 629e: 9dd3

Преобразование IPv4-адрес в шестнадцатеричный IPv6-адрес в Python

...