1#	$OpenBSD: Makefile,v 1.15 2020/12/30 21:40:33 kn Exp $
2
3# The following ports must be installed:
4#
5# scapy               powerful interactive packet manipulation in python
6
7.if ! exists(/usr/local/bin/scapy)
8regress:
9	@echo Install scapy package to run this regress.
10	@echo SKIPPED
11.endif
12
13# This test needs a manual setup of two machines
14# Set up machines: LOCAL REMOTE
15# LOCAL is the machine where this makefile is running.
16# REMOTE is running OpenBSD with ARP to test the Address Resolution Protocol.
17# FAKE is an non existing machine, its IP is used in the tests.
18# OTHER is an IP on REMOTE, but configured on another interface.
19# OTHER_FAKE is an non existing IP on another interface.
20# REMOTE_SSH is the hostname to log in on the REMOTE machine.
21
22# Configure Addresses on the machines.
23# Adapt interface and addresse variables to your local setup.
24#
25LOCAL_IF ?=
26LOCAL_MAC ?=
27REMOTE_MAC ?=
28FAKE_MAC ?= 12:34:56:78:9a:bc
29PROXY_MAC ?= 00:90:27:bb:cc:dd
30REMOTE_SSH ?=
31
32LOCAL_ADDR ?= 10.188.70.17
33REMOTE_ADDR ?= 10.188.70.70
34FAKE_ADDR ?= 10.188.70.188
35OTHER_ADDR ?= 10.188.211.70
36OTHER_FAKE_ADDR ?= 10.188.211.188
37
38.if empty (LOCAL_IF) || empty (LOCAL_MAC) || empty (REMOTE_MAC) || \
39    empty (FAKE_MAC) || empty (REMOTE_SSH) || empty (LOCAL_ADDR) || \
40    empty (REMOTE_ADDR) || empty (FAKE_ADDR) || empty (OTHER_ADDR) || \
41    empty (OTHER_FAKE_ADDR)
42regress:
43	@echo this tests needs a remote machine to operate on
44	@echo LOCAL_IF LOCAL_MAC REMOTE_MAC FAKE_MAC REMOTE_SSH LOCAL_ADDR
45	@echo REMOTE_ADDR FAKE_ADDR OTHER_ADDR OTHER_FAKE_ADDR are empty
46	@echo fill out these variables for additional tests
47	@echo SKIPPED
48.endif
49
50.if ! empty (REMOTE_SSH)
51.if make (regress) || make (all)
52.BEGIN:
53	${SUDO} true
54	ssh -t ${REMOTE_SSH} ${SUDO} true
55	@echo
56.endif
57.endif
58
59# Create python include file containing the addresses.
60addr.py: Makefile
61	rm -f $@ $@.tmp
62	echo 'LOCAL_IF = "${LOCAL_IF}"' >>$@.tmp
63.for var in LOCAL REMOTE FAKE
64	echo '${var}_MAC = "${${var}_MAC}"' >>$@.tmp
65.endfor
66.for var in LOCAL REMOTE FAKE OTHER OTHER_FAKE
67	echo '${var}_ADDR = "${${var}_ADDR}"' >>$@.tmp
68.endfor
69	mv $@.tmp $@
70
71# Set variables so that make runs with and without obj directory.
72# Only do that if necessary to keep visible output short.
73.if ${.CURDIR} == ${.OBJDIR}
74PYTHON =	python3 -u ./
75.else
76PYTHON =	PYTHONPATH=${.OBJDIR} python3 -u ${.CURDIR}/
77.endif
78
79# Clear local and remote ARP cache.
80REGRESS_SETUP +=	clean-arp
81REGRESS_CLEANUP +=	clean-arp
82clean-arp:
83	${SUDO} arp -da
84	ssh ${REMOTE_SSH} ${SUDO} arp -da
85
86# Clear ARP cache and ping all addresses.  This ensures that
87# the IP addresses are configured and all routing table are set up
88# to allow bidirectional packet flow.
89REGRESS_TARGETS +=	run-ping
90run-ping:
91.for ip in LOCAL_ADDR REMOTE_ADDR
92	@echo Check ping ${ip}
93	ping -n -c 1 ${${ip}}
94.endfor
95
96# Send an ARP request from the local machine, asking for the remote
97# machine's MAC.  Target MAC is broadcast, Target IP is remote address.
98# Check that all fields of the answer are filled out correctly.
99# Check that the remote machine has the local IP and MAC in its ARP table.
100REGRESS_TARGETS +=	run-arp-request
101run-arp-request: addr.py
102	@echo Send ARP Request for remote address and insert local address
103	${SUDO} ${PYTHON}arp_request.py
104	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
105	grep '^${LOCAL_ADDR} .* ${LOCAL_MAC} ' arp.log
106
107# Send an ARP request from the local machine, but use a multicast MAC
108# as sender.  Although there is a special check in in_arpinput(),
109# this must be answered.  The ARP entry on the remote machine for the
110# local address is changed to the multicast MAC.
111# Check that all fields of the answer are filled out correctly.
112# Check that the remote machine overwrites the local address.
113REGRESS_TARGETS +=	run-arp-multicast
114run-arp-multicast: addr.py
115	@echo Send ARP Request and overwrite entry with multicast ethernet
116	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
117	ssh ${REMOTE_SSH} ${SUDO} arp -s ${LOCAL_ADDR} ${LOCAL_MAC} temp
118	scp ${REMOTE_SSH}:/var/log/messages old.log
119	${SUDO} ${PYTHON}arp_multicast.py
120	scp ${REMOTE_SSH}:/var/log/messages new.log
121	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
122	ssh ${REMOTE_SSH} ${SUDO} arp -d ${LOCAL_ADDR}
123	diff old.log new.log | grep '^> ' >diff.log
124	grep 'bsd: arp info overwritten for ${LOCAL_ADDR} by 33:33:33:33:33:33' diff.log
125	grep '^${LOCAL_ADDR} .* 33:33:33:33:33:33 ' arp.log
126
127# Send an ARP probe from the local machine with the remote IP as
128# target.  Sender MAC is local and IP is 0.  The remote machine must
129# defend its IP address with an ARP reply.
130# Check that all fields of the answer are filled out correctly.
131REGRESS_TARGETS +=	run-arp-probe
132run-arp-probe: addr.py
133	@echo Send ARP Probe for existing address and expect correct reply
134	${SUDO} ${PYTHON}arp_probe.py
135
136# Send ARP request with broadcast MAC as sender.
137# Check that no answer is received.
138# Check that the remote machine rejects the broadcast sender.
139REGRESS_TARGETS +=	run-arp-broadcast
140run-arp-broadcast: addr.py
141	@echo Send ARP Request with broadcast as sender hardware address
142	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
143	scp ${REMOTE_SSH}:/var/log/messages old.log
144	${SUDO} ${PYTHON}arp_broadcast.py
145	scp ${REMOTE_SSH}:/var/log/messages new.log
146	diff old.log new.log | grep '^> ' >diff.log
147	grep 'bsd: arp: ether address is broadcast for IP address ${LOCAL_ADDR}' diff.log
148
149# The local machine announces that it has taken the remote machine's
150# IP.  The sender is the local machines MAC and the remote IP.  The
151# remote machine must defend its IP address with an ARP reply.
152# Check that all fields of the answer are filled out correctly.
153# Check that the remote machine reports an duplicate address.
154# Check that the remote machine keeps its local ARP entry.
155REGRESS_TARGETS +=	run-arp-announcement
156run-arp-announcement: addr.py
157	@echo Send ARP Announcement for existing address
158	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
159	scp ${REMOTE_SSH}:/var/log/messages old.log
160	${SUDO} ${PYTHON}arp_announcement.py
161	scp ${REMOTE_SSH}:/var/log/messages new.log
162	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
163	diff old.log new.log | grep '^> ' >diff.log
164	grep 'bsd: duplicate IP address ${REMOTE_ADDR} sent from ethernet address ${LOCAL_MAC}' diff.log
165	grep '^${REMOTE_ADDR} .* ${REMOTE_MAC} .* permanent * l$$' arp.log
166
167# The local machine sends an gratuitous ARP reply for the remote IP
168# with its local MAC.
169# Check that no answer is received.
170# Check that the remote machine reports an duplicate address.
171# Check that the remote machine keeps its local ARP entry.
172REGRESS_TARGETS +=	run-arp-gratuitous
173run-arp-gratuitous: addr.py
174	@echo Send Gratuitous ARP for existing address
175	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
176	scp ${REMOTE_SSH}:/var/log/messages old.log
177	${SUDO} ${PYTHON}arp_gratuitous.py
178	scp ${REMOTE_SSH}:/var/log/messages new.log
179	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
180	diff old.log new.log | grep '^> ' >diff.log
181	grep 'bsd: duplicate IP address ${REMOTE_ADDR} sent from ethernet address ${LOCAL_MAC}' diff.log
182	grep '^${REMOTE_ADDR} .* ${REMOTE_MAC} .* permanent * l$$' arp.log
183
184# Add a permanent entry on the remote machine for a fake MAC and IP.
185# Send a request form the local machine, indicating with the local
186# MAC and the fake IP as sender that it claims the fake address.
187# Check that no answer is received.
188# Check that the attempt to overwrite the permanent entry is logged.
189# Check that the remote machine keeps its permanent ARP entry.
190REGRESS_TARGETS +=	run-arp-permanent
191run-arp-permanent: addr.py
192	@echo Send ARP Request to change permanent fake address
193	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
194	ssh ${REMOTE_SSH} ${SUDO} arp -s ${FAKE_ADDR} ${FAKE_MAC} permanent
195	scp ${REMOTE_SSH}:/var/log/messages old.log
196	${SUDO} ${PYTHON}arp_fake.py
197	scp ${REMOTE_SSH}:/var/log/messages new.log
198	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
199	ssh ${REMOTE_SSH} ${SUDO} arp -d ${FAKE_ADDR}
200	diff old.log new.log | grep '^> ' >diff.log
201	grep 'bsd: arp: attempt to overwrite permanent entry for ${FAKE_ADDR} by ${LOCAL_MAC}' diff.log
202	grep '^${FAKE_ADDR} .* ${FAKE_MAC} .* permanent * $$' arp.log
203
204# The remote machine has a second address on another interface.
205# The local machine claims this address in its sender IP.
206# Check that no answer is received.
207# Check that the attempt to overwrite the permanent entry is logged.
208# Check that the remote machine keeps its local ARP entry.
209REGRESS_TARGETS +=	run-arp-address
210run-arp-address: addr.py
211	@echo Send ARP Request to change address on other interface
212	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
213	scp ${REMOTE_SSH}:/var/log/messages old.log
214	${SUDO} ${PYTHON}arp_other.py
215	scp ${REMOTE_SSH}:/var/log/messages new.log
216	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
217	diff old.log new.log | grep '^> ' >diff.log
218	grep 'bsd: arp: attempt to overwrite permanent entry for ${OTHER_ADDR} by ${LOCAL_MAC}' diff.log
219	grep '^${OTHER_ADDR} .* permanent * l$$' arp.log
220
221# The remote machine has a second address on another interface.  Add
222# a temporary ARP entry for a fake address in this network on the
223# remote machine.  The local machine tries to overwrite this address
224# with its own MAC.
225# Check that no answer is received.
226# Check that the attempt to overwrite the permanent entry is logged.
227# Check that the remote machine keeps its ARP entry.
228REGRESS_TARGETS +=	run-arp-temporary
229run-arp-temporary: addr.py
230	@echo Send ARP Request to change temporary entry on other interface
231	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
232	ssh ${REMOTE_SSH} ${SUDO} arp -s ${OTHER_FAKE_ADDR} ${FAKE_MAC} temp
233	scp ${REMOTE_SSH}:/var/log/messages old.log
234	${SUDO} ${PYTHON}arp_otherfake.py
235	scp ${REMOTE_SSH}:/var/log/messages new.log
236	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
237	ssh ${REMOTE_SSH} ${SUDO} arp -d ${OTHER_FAKE_ADDR}
238	diff old.log new.log | grep '^> ' >diff.log
239	grep 'bsd: arp: attempt to overwrite entry for ${OTHER_FAKE_ADDR} on .* by ${LOCAL_MAC} on .*' diff.log
240	grep '^${OTHER_FAKE_ADDR} .* ${FAKE_MAC} ' arp.log
241
242# The remote machine has a second address on another interface.  Create
243# an incomplete ARP entry for a fake address in this network on the
244# remote machine with an unsuccessful ping.  The local machine tries
245# to overwrite this address with its own MAC.
246# Check that no answer is received.
247# Check that the attempt to add an entry is logged.
248# Check that the remote machine keeps its incomplete ARP entry.
249REGRESS_TARGETS +=	run-arp-incomplete
250run-arp-incomplete: addr.py
251	@echo Send ARP Request filling an incomplete entry on other interface
252	ssh ${REMOTE_SSH} logger -t "arp-regress[$$$$]" $@
253	ssh ${REMOTE_SSH} ${SUDO} ping -n -w 1 -c 1 ${OTHER_FAKE_ADDR} || true
254	scp ${REMOTE_SSH}:/var/log/messages old.log
255	${SUDO} ${PYTHON}arp_otherfake.py
256	scp ${REMOTE_SSH}:/var/log/messages new.log
257	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
258	ssh ${REMOTE_SSH} ${SUDO} arp -d ${OTHER_FAKE_ADDR}
259	diff old.log new.log | grep '^> ' >diff.log
260	grep 'bsd: arp: attempt to add entry for ${OTHER_FAKE_ADDR} on .* by ${LOCAL_MAC} on .*' diff.log
261	grep '^${OTHER_FAKE_ADDR} .* (incomplete) ' arp.log
262
263# Publish a proxy ARP entry on the remote machine for a fake address.
264# The local machine requests this IP as a the target.
265# Check that all fields of the answer are filled out correctly.
266# Check that the remote machine has a public ARP entry.
267REGRESS_TARGETS +=	run-arp-proxy
268run-arp-proxy: addr.py
269	@echo Send ARP Request for fake address that is proxied
270	ssh ${REMOTE_SSH} ${SUDO} arp -s ${FAKE_ADDR} ${PROXY_MAC}
271	ssh ${REMOTE_SSH} ${SUDO} arp -s ${FAKE_ADDR} ${FAKE_MAC} pub
272	${SUDO} ${PYTHON}arp_proxy.py
273	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
274	ssh ${REMOTE_SSH} ${SUDO} arp -d ${FAKE_ADDR}
275	ssh ${REMOTE_SSH} ${SUDO} arp -d ${FAKE_ADDR}
276	grep '^${FAKE_ADDR} .* ${FAKE_MAC} .* static * p$$' arp.log
277
278# Enter a static ARP entry on the remote machine for a fake address,
279# but do not publish it.  The local machine requests this IP as a the
280# target.
281# Check that no answer is received.
282# Check that the remote machine has a static ARP entry.
283REGRESS_TARGETS +=	run-arp-nonproxy
284run-arp-nonproxy: addr.py
285	@echo Send ARP Request for fake address that is not published
286	ssh ${REMOTE_SSH} ${SUDO} arp -s ${FAKE_ADDR} ${FAKE_MAC}
287	${SUDO} ${PYTHON}arp_nonproxy.py
288	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
289	ssh ${REMOTE_SSH} ${SUDO} arp -d ${FAKE_ADDR}
290	grep '^${FAKE_ADDR} .* ${FAKE_MAC} .* static * $$' arp.log
291
292# Publish a proxy ARP entry on the remote machine for a fake address
293# on another interface.  The local machine requests this IP.  As the
294# proxy entry is for another interface, it must not be answered.
295# Check that no answer is received.
296# Check that the remote machine has a public ARP entry.
297REGRESS_TARGETS +=	run-arp-otherproxy
298run-arp-otherproxy: addr.py
299	@echo Send ARP Request for address proxied on another interface
300	ssh ${REMOTE_SSH} ${SUDO} arp -s ${OTHER_FAKE_ADDR} ${FAKE_MAC} pub
301	${SUDO} ${PYTHON}arp_otherproxy.py
302	ssh ${REMOTE_SSH} ${SUDO} arp -an >arp.log
303	ssh ${REMOTE_SSH} ${SUDO} arp -d ${OTHER_FAKE_ADDR}
304	grep '^${OTHER_FAKE_ADDR} .* ${FAKE_MAC} .* static * p$$' arp.log
305
306CLEANFILES +=		addr.py *.pyc *.log
307
308.include <bsd.regress.mk>
309