2

Good afternoon everyone,

my coding skills are not quite on the level required to do socket programming myself and I was wondering if someone here can help me with what I need - which is fairly simple:

  • crafting own PIM (multicast) join packet.

I want to send a "dummy" PIM join packets to a neighbouring device without really bothering maintaining any PIM adjacencies/(hellos). Ideally I want to end-up with a function that accepts a few arguments:

def send_dummy_join(group, rp, source_ip):
  // send 1 join every time this function is called

Ideally I need it to run using python3 not using external modules (e.g. scapy)

Another problem I have & don't quite understand how to solve is crafting a packet with a source address which doesn't belong to any network interface on the system. I know scapy can do this I only don't quite understand how to craft it myself.

Thanks in advance for all your help. Much appreciated!

Some external information.

PIM headers

http://www.networksorcery.com/enp/protocol/pim.htm

PIM.c implementation

https://github.com/troglobit/pimd/blob/master/src/pim.c

Community
  • 1
  • 1
Bona Fide
  • 23
  • 2

1 Answers1

1

I will most probably (fully rightfully though ;-)) get publicly lynched for the following piece of code, but as one network engineer to another check out the code below.

A few more bits to bear in mind - You need to "establish adjacency" first (exchange some hello packets) or your PIM joins will get ignored by the upstream router (hence the dummy hello function added).

Furthermore, the "Upstream Neighbour IP" is also necessary when sending PIM joins.

import socket
from struct import pack, iter_unpack
from functools import reduce    

def checksum(data):
    sum = reduce(lambda x, y: x + y, iter_unpack("!H",data))
    s = reduce(lambda x, y: x + y, sum)

    while (s >> 16):
        s = (s & 0xFFFF) + (s >> 16)
    s = ~s & 0xffff

    return s

def send_dummy_hello():
    PIM_GROUP = '224.0.0.13'

    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_PIM)
    my_packet=pack('!BBH3H4H4H4H', 32, 0, 24707, 1, 2, 105, 20, 4, 16121,
        16078, 19, 4, 0, 1, 21, 4, 256, 0)

    sock.sendto(my_packet, (PIM_GROUP,0))

def send_dummy_join(group, rp_addr, neighbor_ip):
    PIM_GROUP = '224.0.0.13'

    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_PIM)

    pim_ver    = 35
    pim_res    = 0
    pktchksum  = 0
    pim_opts   = 256
    neighbor   = socket.inet_aton(neighbor_ip)
    ngroups    = 1
    holdtime   = 210
    subnet     = socket.inet_aton('1.0.0.32')
    group_a    = socket.inet_aton(group)
    num_joins  = 1
    num_prunes = 0
    rrp_subnet = socket.inet_aton('1.0.7.32')
    rp_address = socket.inet_aton(rp_addr)

    my_packet = pack('!BB2H4sHH4s4sHH4s4s', pim_ver, pim_res, pktchksum, pim_opts,
        neighbor, ngroups, holdtime, subnet, group_a, num_joins, num_prunes, 
        rrp_subnet, rp_address)

    pktchksum = checksum(my_packet)
    my_packet = pack('!BB2H4sHH4s4sHH4s4s', pim_ver, pim_res, pktchksum, pim_opts,
        neighbor, ngroups, holdtime, subnet, group_a, num_joins, num_prunes, 
        rrp_subnet, rp_address)

    sock.sendto(my_packet, (PIM_GROUP,0))
    print (f'PIM Join sent to {neighbor_ip} for {group} & RP {rp_addr}')

>>>send_dummy_hello() 
>>>send_dummy_join('239.10.20.30','192.168.0.1','10.0.0.102')


I tested this with EVE-NG and it (magically!) worked :-)

EDIT:

The code is now edited to support header checksum calculation. I think this is now complete! :-)

Danail Petrov
  • 1,875
  • 10
  • 12
  • 1
    Hey this is great! It absolutely did the job and it will be amazing if we can get the checksum calculated within the script. – Bona Fide Jan 19 '20 at 17:24
  • 1
    This is absolutely brilliant. Thank you so very much. I did some tests and it works a treat. Thank you!!! – Bona Fide Jan 20 '20 at 13:10