derhuerst / node-awdl

Send data via Apple Wireless Direct Link (AWDL) using JavaScript.
https://github.com/derhuerst/node-awdl
ISC License
8 stars 0 forks source link

don't spawn nc, open socket directly #1

Open derhuerst opened 4 years ago

derhuerst commented 4 years ago

Right now, this package spawns nc a.k.a. netcat to listen for awdl0 traffic; This is a bit hacky, doing it from within Node via its UDP socket API/TCP socket API would be cleaner.

I'm not an expert, and I failed miserably at porting these working implementations:

derhuerst commented 4 years ago

This is my prototype:

// const {parse: parseIpAddress} = require('ipaddr.js')
const {networkInterfaces} = require('os')
const {createSocket} = require('dgram')
const {decode} = require('dns-packet')

// const isIPv6Loopback = (address) => {
//  const firstPart = parseIpAddress(address).parts[0] || 0
//  return firstPart.toString(2).slice(0, 10) === '1111111010'
// }
const isProperInterface = ({family, address}) => {
    // return family === 'IPv6' && !isIPv6Loopback(address)
    return family === 'IPv6'
}

const awdl0 = (networkInterfaces().awdl0 || []).find(isProperInterface)
if (!awdl0) throw new Error('no awdl0 interface found')
console.error(awdl0)
// const en0 = (networkInterfaces().en0 || []).find(isProperInterface)
// if (!en0) throw new Error('no en0 interface found')

const SOL_SOCKET = 0x1
// https://github.com/torvalds/linux/blob/a2d79c7174aeb43b13020dd53d85a7aefdd9f3e5/include/uapi/asm-generic/socket.h#L27
const SO_REUSEPORT = 15
// https://opensource.apple.com/source/xnu/xnu-4570.31.3/bsd/sys/socket.h :318
const SO_RECV_ANYIF = 0x1104
// https://www.iana.org/assignments/ipv6-multicast-addresses/ipv6-multicast-addresses.xhtml
const MDNSv6_MULTICAST_GROUP = 'ff02::fb'

const AWDL_CLASS = 'UNKNOWN_32769' // todo

// const ip = '::'
const ip = awdl0.address
const scope = '%awdl0'

const onMessage = (msg) => {
    const {type, questions, answers} = decode(msg)
    console.log(type, questions, answers)
}

const socket = createSocket({
    type: 'udp6',
    reuseAddr: true,
    ipv6Only: true
})

socket.bind(5353, (err) => {
// socket.bind(5353, ip, (err) => {
// socket.bind(5353, ip + scope, (err) => {
// socket.bind(5353, '::' + scope, (err) => {
    if (err) {
        console.error(err)
        process.exit(1)
    }
    socket.on('error', console.error)
    socket.on('message', onMessage)

    // this doesn't work yet! not receiving packages :(
    socket.addMembership(MDNSv6_MULTICAST_GROUP, ip + scope)
    setsockopt(socket, SOL_SOCKET, SO_RECV_ANYIF, 1)
})
derhuerst commented 2 years ago

new Python zeroconf implementation: https://github.com/jstasiak/python-zeroconf/blob/88323d0c7866f78edde063080c63a72c6e875772/zeroconf/_utils/net.py#L216-L323