diff --git a/arpa.sql b/arpa.sql new file mode 100644 index 0000000..86681be --- /dev/null +++ b/arpa.sql @@ -0,0 +1,90 @@ +-- This file control sum +SET vars.csum TO :'csum'; +-- This zone copy hostname +SET vars.ns TO :'NSERVER'; + +DO $$ +-- Наполнение + +DECLARE + v_domain text; -- domain name + v_domain_id integer; -- internal domain id + v_ns_admin text := 'hostmaster.example.ru'; -- master DNS admin email + v_soa text; -- zone SOA + v_prefixes cidr[] := ARRAY[ + '10.0.0.0/8', -- Private-Use Networks + '100.64.0.0/10', -- CG-NAT + '127.0.0.0/8', -- Loopback + '172.16.0.0/12', -- LLA + '169.254.0.0/16', -- Private-Use Networks + '192.0.0.0/24', -- IETF Protocol Assignments + '192.0.2.0/24', -- TEST-NET-1 + '192.88.99.0/24', -- 6to4 Relay Anycast + '192.168.0.0/16', -- Private-Use Networks + '198.18.0.0/15', -- Network Interconnect Device Benchmark Testing + '198.51.100.0/24', -- TEST-NET-2 + '203.0.113.0/24' -- TEST-NET-3 + ]; + v_prefixes24 cidr[]; + v_prefix cidr; + v_arr text[]; + +BEGIN + -- пересобираем список префиксов по /24 + -- ToDo: префиксы выходящие за границы /8 =< prefix < /24 пропускать + FOREACH v_prefix IN ARRAY v_prefixes LOOP + -- получили размерность + FOR i IN 0 .. 2^(24 - masklen(v_prefix))-1 LOOP + -- добавили каждую /24 + v_prefixes24 := ARRAY_APPEND(v_prefixes24, set_masklen(v_prefix + 256 * i, 24)); + -- RAISE NOTICE '% %: %', v_prefix, i, set_masklen(v_prefix + 256 * i, 24); + END LOOP; + END LOOP; + + FOREACH v_prefix IN ARRAY v_prefixes24 LOOP + -- собираем имя зоны + v_domain := concat_ws('.', -- собираем полностью итоговый v_domain в формате $oct3.$oct2.$oct1.in-addr.arpa + array_to_string( -- результат превращаем в текст + array_reverse( -- разворачиваем массив в обратном направлении для in-addr.arpa + trim_array( -- отрезаем от массива последний октет с маской, так как для /24 в in-addr.arpa надо 3 октета + string_to_array(v_prefix::text, '.'), -- v_prefix переводим в text и разбираем в массив через '.' + 1 + ) + ),'.' + ), + 'in-addr.arpa' + ); + + SELECT INTO v_domain_id id FROM domains WHERE name = v_domain; + IF NOT FOUND THEN + -- зона отсутствует, будем генерить зону по умолчанию + RAISE NOTICE 'Stub generator for prefix:% zone:%', v_prefix, v_domain; + ELSE + -- зона уже создана, пропустить stub-функционал + RAISE NOTICE 'zone:% already exists, skip stub generation', v_domain; + CONTINUE; + END IF; + + /* + чексуммы у зоны нет, поэтому достаточно будет первого запуска по + файлу со спецификой зоны, чтобы затереть зону-заглушку + получаем/создаём домен ID + */ + v_domain_id := domain_id(v_domain); + + -- собираем SOA + v_soa := soa_mk(v_domain_id, v_ns_admin); + + -- в принципе если мы здесь, то предполагается, что зоны такой не существовало + -- и записей, соответственно, нет. но тем не менее + DELETE FROM records WHERE domain_id = v_domain_id; + + -- генерим зону по умолчанию + INSERT INTO records (domain_id, name, ttl, type, prio, content) VALUES + (v_domain_id, v_domain, 10800, 'SOA', 0, v_soa) + , (v_domain_id, v_domain, 10800, 'NS', 0, 'ns1.example.ru') + , (v_domain_id, v_domain, 10800, 'NS', 0, 'ns2.example.ru') + ; + END LOOP; +END; +$$;