Skip to content

Instantly share code, notes, and snippets.

@cmol
Last active January 30, 2021 23:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cmol/9f0b9efec4bcc42340ea57f6cc3b4d28 to your computer and use it in GitHub Desktop.
Save cmol/9f0b9efec4bcc42340ea57f6cc3b4d28 to your computer and use it in GitHub Desktop.
require 'socket'
require 'ipaddr'
def get_interface_info(name)
ifaddrs = Socket.getifaddrs.reject do |ifaddr|
!ifaddr.addr&.ipv6_linklocal? || (ifaddr.flags & Socket::IFF_MULTICAST == 0)
end
ifaddrs.select! {|ifaddr| ifaddr.name == name } if name
ifaddrs.map {|ifaddr| [ifaddr.name, ifaddr.ifindex, ifaddr.addr.ip_address] }
end
# Set-up and prepare socket
def create_socket(multicast_addr, multicast_port, ifindex)
UDPSocket.new(Socket::AF_INET6).tap do | s |
ip = IPAddr.new(multicast_addr).hton + [ifindex].pack('I')
s.setsockopt(Socket::IPPROTO_IPV6, Socket::IPV6_JOIN_GROUP, ip)
s.setsockopt(Socket::IPPROTO_IPV6, Socket::IPV6_MULTICAST_HOPS, [1].pack('I'))
s.setsockopt(Socket::IPPROTO_IPV6, Socket::IPV6_MULTICAST_IF, [ifindex].pack('I'))
s.bind("::", multicast_port)
end
end
# Sender thead
def send_request(socket, linklocal_addr, multicast_addr, multicast_port,
flags)
Thread.new do
# Ensure that we are listening before talking
sleep 0.1
puts "========= Sending echo REQUEST from #{linklocal_addr}"
socket.send("[REQUEST] Hello from #{linklocal_addr}",
flags, multicast_addr, multicast_port)
end
end
def echo_listener(socket, linklocal_addr, multicast_addr, multicast_port,
flags, msg_length)
loop do
# Listen for messages of up to specified length
message, client = socket.recvfrom(msg_length)
# Extract client information given as array and log connection
addr_info = Addrinfo.new(client)
# We are not interested in messages from our selves
next if addr_info.ip_address == linklocal_addr
# Write out the received message
puts message
# Only reply if a request is send. If not, we will make infinite packet
# loops in our network
if(message.split.first == "[REQUEST]")
puts "========= Sending echo REPLY to #{addr_info.ip_address}"
socket.send("[REPLY] Hello from #{addr_info.ip_address}",
flags, multicast_addr, multicast_port)
end
end
end
if __FILE__==$0
MULTICAST_ADDR = "ff02::beeb"
MULTICAST_PORT = 12345
MSG_LENGTH = 256
FLAGS = 0
# Call with interface name if you want to use another interface than the
# first one presented from getifaddrs
interface_name, ifindex, linklocal_addr = get_interface_info(ARGV[0]).first
puts "Using local interface #{interface_name} with address #{linklocal_addr}"
socket = create_socket(MULTICAST_ADDR, MULTICAST_PORT, ifindex)
send_request(socket, linklocal_addr, MULTICAST_ADDR, MULTICAST_PORT, FLAGS)
echo_listener(socket, linklocal_addr, MULTICAST_ADDR, MULTICAST_PORT, FLAGS,
MSG_LENGTH)
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment