Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
6b8ce9e
create_send_sock() - improve error handling
Alphix Feb 4, 2024
2ca8a23
create_send_sock() - reorganise function a bit
Alphix Feb 4, 2024
5cf1522
create_send_sock() - dynamically allocate sockdata
Alphix Feb 4, 2024
05c6c07
Use stdbool.h to define booleans
Alphix Feb 4, 2024
afedb26
Use a linked list to keep track of send socks
Alphix Feb 4, 2024
0552d4d
Add list.h
Alphix Feb 4, 2024
ccfd792
Rename parse() as parse_subnet() and simplify error handling
Alphix Feb 4, 2024
5b7e840
Simplify parse_subnet()
Alphix Feb 4, 2024
c24631a
Convert the subnet black/whitelists to linked lists
Alphix Feb 4, 2024
7c72575
Add subnet_match() helper function
Alphix Feb 4, 2024
6bdef46
Create some socket/subnet print helpers
Alphix Feb 4, 2024
5a737a1
Add a signal pipe
Alphix Feb 4, 2024
c1cc11a
Switch from select() to poll()
Alphix Feb 4, 2024
f4d788f
Turn receiving sockets into a list as well
Alphix Feb 4, 2024
e551477
Rename struct if_sock to send_sock
Alphix Feb 4, 2024
9754065
Support IPv6 in recvfrom
Alphix Feb 4, 2024
c830507
Support IPv6 in subnets (blacklist/whitelist)
Alphix Feb 4, 2024
b842c61
Support IPv6 in recv_sock()
Alphix Feb 5, 2024
5cd3579
Use IP_MULTICAST_IF instead of SO_BINDTODEVICE
Alphix Feb 6, 2024
6652c4d
Use IPv4/IPv6 agnostic storage for send_sock addresses
Alphix Feb 6, 2024
e49c9c6
Add a separate create_send_sock6() function
Alphix Feb 6, 2024
2e27cce
Add IPV6_V6ONLY to create_recv_sock6()
Alphix Feb 6, 2024
9d65bcc
Split send_socks into separate v4/v6 lists
Alphix Feb 6, 2024
9336530
Move packet repetition logic to separate functions
Alphix Feb 6, 2024
d88f61c
Move packet reception to a separate function
Alphix Feb 6, 2024
14282d8
Reorganize structs a bit
Alphix Feb 6, 2024
32b08bc
Create a struct for addr/mask/net tuples
Alphix Feb 6, 2024
8bcbb1c
Remove struct subnet, use struct addr_mask instead
Alphix Feb 6, 2024
d410c0f
Create separate send_sock structs for IPv4 and IPv6
Alphix Feb 6, 2024
2d41311
Change struct send_sock6 to include a list of nets
Alphix Feb 6, 2024
1e1d59c
Add proper address determination to create_send_sock6()
Alphix Feb 6, 2024
1a39f02
Split recv_packet() into v4/v6 versions
Alphix Feb 6, 2024
cad3763
Improve recv_packet6() to get ifindex
Alphix Feb 6, 2024
f37d382
Split subnet_match into v4/v6 versions
Alphix Feb 7, 2024
cf08782
Split send_packet() into v4/v6 functions
Alphix Feb 7, 2024
1ec0df1
Fix a bug in the IPv6 subnet matching function
Alphix Feb 7, 2024
bf48652
Use the new same_network() function in other places as well
Alphix Feb 7, 2024
d887376
Add a same_address() helper function
Alphix Feb 7, 2024
4681357
Make more use of the log_message() function
Alphix Feb 7, 2024
7cc7e2c
Add a malloc() wrapper
Alphix Feb 7, 2024
d39410b
Add -4 and -6 command line options and update help text
Alphix Feb 7, 2024
756b854
Update README
Alphix Feb 7, 2024
75966e2
Add a .gitignore file
Alphix Feb 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.o
_hgversion
mdns-repeater
mdns-repeater-*.zip
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ CFLAGS+= -DHGVERSION="\"${HGVERSION}\""

all: mdns-repeater

mdns-repeater.o: _hgversion
mdns-repeater.o: _hgversion list.h

mdns-repeater: mdns-repeater.o

Expand Down
11 changes: 8 additions & 3 deletions README.txt
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
mdns-repeater
==============
mdns-repeater is a Multicast DNS repeater for Linux. Multicast DNS uses the
224.0.0.251 address, which is "administratively scoped" and does not
leave the subnet.
224.0.0.251 (IPv4) and ff02::fb (IPv6) addresses, which are "administratively
scoped" and do not leave the subnet.

This program re-broadcast mDNS packets from one interface to other interfaces.
It was written primarily to be run on my Linksys WRT54G which runs dd-wrt,
since my wireless network is on a different subnet from my wired network and
I would like my zeroconf devices to work properly across the two subnets.

Since the mDNS protocol sends the AA records in the packet itself, the
Since the mDNS protocol sends the A records in the packet itself, the
repeater does not need to forge the source address. Instead, the source
address is of the interface that repeats the packet.

For IPv6, some devices send AAAA records containing a link-local address.
The repeater does currently not change such records, meaning that hosts
might be advertised with unreachable addresses.


USAGE
-----
Expand All @@ -32,6 +36,7 @@ long as you abide by the software license.
LICENSE
--------
Copyright (C) 2011 Darell Tan
Copyright (C) 2024 David Härdeman <david@hardeman.nu>

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
Expand Down
155 changes: 155 additions & 0 deletions list.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* This is the doubly linked list implementation taken from the Linux
* kernel (26 June 2020).
*
* The only modifications are the ones necessary to make it compile
* outside the kernel tree, and to remove some functions which are not
* necessary (like hlist*).
*/

#ifndef _LINUX_LIST_H
#define _LINUX_LIST_H

struct list_head {
struct list_head *next, *prev;
};

#define offsetof(TYPE, MEMBER) ((size_t) & ((TYPE *)0)->MEMBER)

#define container_of(ptr, type, member) \
__extension__({ \
const typeof(((type *)0)->member) *__mptr = (ptr); \
(type *)((char *)__mptr - offsetof(type, member)); \
})

/*
* Simple doubly linked list implementation.
*
* Some of the internal functions ("__xxx") are useful when
* manipulating whole lists rather than single entries, as
* sometimes we already know the next/prev entries and we can
* generate better code by using them directly rather than
* using the generic single-entry routines.
*/

#define LIST_HEAD_INIT(name) \
{ \
&(name), &(name) \
}

#define LIST_HEAD(name) struct list_head name = LIST_HEAD_INIT(name)

/**
* INIT_LIST_HEAD - Initialize a list_head structure
* @list: list_head structure to be initialized.
*
* Initializes the list_head to point to itself. If it is a list header,
* the result is an empty list.
*/
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
list->prev = list;
}

/*
* Insert a new entry between two known consecutive entries.
*
* This is only for internal list manipulation where we know
* the prev/next entries already!
*/
static inline void __list_add(struct list_head *new, struct list_head *prev,
struct list_head *next)
{
next->prev = new;
new->next = next;
new->prev = prev;
prev->next = new;
}

/**
* list_add - add a new entry
* @new: new entry to be added
* @head: list head to add it after
*
* Insert a new entry after the specified head.
* This is good for implementing stacks.
*/
static inline void list_add(struct list_head *new, struct list_head *head)
{
__list_add(new, head, head->next);
}

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
* Note: list_empty() on entry does not return true after this, the entry is
* in an undefined state.
*/
static inline void list_del(struct list_head *entry)
{
entry->next->prev = entry->prev;
entry->prev->next = entry->next;
}

/**
* list_empty - tests whether a list is empty
* @head: the list to test.
*/
static inline int list_empty(const struct list_head *head)
{
return head->next == head;
}

/**
* list_entry - get the struct for this entry
* @ptr: the &struct list_head pointer.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*/
#define list_entry(ptr, type, member) container_of(ptr, type, member)

/**
* list_first_entry - get the first element from a list
* @ptr: the list head to take the element from.
* @type: the type of the struct this is embedded in.
* @member: the name of the list_head within the struct.
*
* Note, that list is expected to be not empty.
*/
#define list_first_entry(ptr, type, member) \
list_entry((ptr)->next, type, member)

/**
* list_next_entry - get the next element in list
* @pos: the type * to cursor
* @member: the name of the list_head within the struct.
*/
#define list_next_entry(pos, member) \
list_entry((pos)->member.next, typeof(*(pos)), member)

/**
* list_for_each_entry - iterate over list of given type
* @pos: the type * to use as a loop cursor.
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry(pos, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member); \
&pos->member != (head); pos = list_next_entry(pos, member))

/**
* list_for_each_entry_safe - iterate over list of given type safe against
* removal of list entry
* @pos: the type * to use as a loop cursor.
* @n: another type * to use as temporary storage
* @head: the head for your list.
* @member: the name of the list_head within the struct.
*/
#define list_for_each_entry_safe(pos, n, head, member) \
for (pos = list_first_entry(head, typeof(*pos), member), \
n = list_next_entry(pos, member); \
&pos->member != (head); pos = n, n = list_next_entry(n, member))

#endif
Loading