#!/usr/bin/env python
# vim: sts=4 sw=4 et

"""
Simple unicast proxy for collectd 3.*.
Binds to 'local' address and forwards all traffic to 'remote'.

[Note]
Since there is no 'host' field in packet it must be prepended to all entries.
Otherwise remote daemon will aggregate similar entries for different hosts.

If given argument is treated as domain name and appended to hostname.
"""

import socket
import struct
import sys

""" Local multicast group/port"""
local  = ("239.192.74.66", 25826)
""" Address to send packets """
remote = ("grid.pp.ru", 35826)

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
mreq = struct.pack("4sl", socket.inet_aton(local[0]), socket.INADDR_ANY)

sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_LOOP, 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
sock.bind(local)

out = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)

class HostMap(dict):
    """ Positive permanent DNS cache """
    def __getitem__(self, ip):
        if ip in self:
            return dict.__getitem__(self, ip)
        try:
            host = socket.getfqdn(ip)
            self[ip] = host
            return host
        except:
            return ip
        
hostmap = HostMap()

if __name__ == "__main__":
    domain = ""
    if len(sys.argv) > 1 and sys.argv[1] != "":
        domain = "." + sys.argv[1]

    while True:
        (buf, addr) = sock.recvfrom(2048)
        newbuf = '\n'.join(map(lambda s: hostmap[addr[0]] + domain + "/" + s, buf.split('\n')))
        sock.sendto(newbuf, remote)
