├── FreeBSD
└── ERL
│ ├── freebsd-ubiquiti-edgerouter-lite.html
│ └── mkerlimage
├── LICENSE
└── scripts
├── check_spf_rules.pl
├── docker-apt-proxy.sh
├── file_holes.pl
├── harp.pl
└── lart.pl
/FreeBSD/ERL/freebsd-ubiquiti-edgerouter-lite.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
5 |
6 | FreeBSD 11.x on Ubiquiti EdgeRouter Lite
7 |
8 |
9 |
22 |
23 |
24 |
25 |
26 |
27 | FreeBSD 11.x on Ubiquiti EdgeRouter Lite
28 |
29 |
30 |
31 | - Update 2017/03/07:
32 | New image available for 11.0-RELEASE-p8
33 |
34 | - Update 2014/09/21:
35 | New version of the build script creates more inodes in
36 | root filesystem.
37 |
38 |
39 |
40 |
41 | The Ubiquiti EdgeRouter Lite is a neat little device that costs less than
42 | US$100, has three Ethernet ports, and can run FreeBSD/mips. It's based on the
43 | Cavium Octeon
44 | CN5020 platform and features a dual core 500mhz MIPS64 processor, 512MB RAM,
45 | and 4GB storage on removable USB.
46 |
47 |
48 |
49 |
50 |
51 |
52 | The EdgeRouter Lite in the foreground, near a Netgear WNDR3700 and a bulky
53 | ISP-provided cablemodem.
54 |
55 |
56 |
57 |
58 | This page provides ready-to-use images of recent FreeBSD releases. Thanks to the
59 | open nature of the EdgeRouter Lite, it's very easy to install and use these
60 | images; just follow the instructions below. Thanks to the fine folks at the
61 | FreeBSD Project, building your own is almost as easy. A script to build them,
62 | along with instructions, is also provided. Special thanks is due to Juli
63 | Mallett and Warner Losh, without whose hard work and generous assistance none
64 | of this would be possible.
65 |
66 |
67 |
68 | Note that this is experimental software which comes with no warranty of
69 | any kind. These builds are works in progress and are not fit or suitable
70 | for any purpose whatsoever. By proceeding you assume all risks.
71 |
72 |
73 |
74 | On my EdgeRouter Lite, the builds provided below are stable and pretty much
75 | fully functional. There are two outstanding issues:
76 |
77 |
78 |
79 | - Performance could be a little better, though it's more than adequate for
80 | my home Internet connection. Basic packet passing between two Gigabit hosts
81 | seems to top out at about 250Mbits/sec.
82 |
83 |
- There is currently no way to pass boot options (such as single-user mode)
84 | to the kernel from U-Boot.
85 |
86 |
87 |
88 | Hardware crypto acceleration via /dev/crypto
seems to work. Use
89 | AES in CBC mode to see a huge speedup over CTR.
90 |
91 |
92 |
93 |
94 |
120 |
121 |
122 | You can also easily build your own image from the
123 | FreeBSD sources using the provided mkerlimage
script, then
124 | return here to continue with installation.
125 |
126 |
127 |
128 |
129 | Getting Started
130 |
131 |
132 |
133 | All you need are the following:
134 |
135 |
136 |
137 | - a computer with a USB port
138 |
139 | -
140 | the device
141 |
142 | -
143 | an RJ-45 serial console cable
144 |
145 | - unless your computer already has a 9-pin serial port,
146 |
147 | a USB-to-DB9 adapter
148 |
149 |
150 | and last but certainly not least,
151 |
152 |
153 | - a Phillips-head screwdriver.
154 |
155 |
156 |
157 | The EdgeRouter's Lite on-board storage is a removable USB drive. Installing
158 | the image is just a matter of opening the device, taking the drive out,
159 | writing the image to it, and putting it back in.
160 |
161 |
162 |
163 |
164 |
165 |
166 | The EdgeRouter Lite with the cover removed. Inside is just a board. The
167 | removable USB storage is on the right.
168 |
169 |
170 |
171 |
172 | Configuring the bootloader afterwards only takes a minute, and then you're
173 | done. If you haven't already set up a serial console for your device, though,
174 | you'll need to do that first.
175 |
176 |
177 |
178 | Serial Console
179 |
180 |
181 |
182 | You may wish to skip to the next section if you
183 | already have a working connection to the serial console of your EdgeRouter
184 | Lite.
185 |
186 |
187 |
188 | The serial console allows you to interact with the device's firmware before
189 | boot, which you will need to do to configure it to boot FreeBSD. Since you'll
190 | need it anyway, the provided images don't enable the ssh server by default,
191 | and you'll log into your new FreeBSD system for the first time this way, as
192 | well.
193 |
194 |
195 |
196 | First, connect the RJ-45 console cable to the port marked "Console" on the
197 | device. Connect the other end to a 9-pin serial port on your computer if you
198 | have one; otherwise connect it to a USB-to-DB9 adapter, and connect that to a
199 | USB port on your computer.
200 |
201 |
202 |
203 | Next, you will need any serial communication software. On FreeBSD and Linux
204 | systems, you can install minicom
by entering one of the
205 | following commands:
206 |
207 |
208 |
209 | System | Command |
210 | FreeBSD 10.0+ | pkg install minicom |
211 |
FreeBSD 9.x | pkg_add -r minicom |
212 |
Debian, Ubuntu, Mint, etc. | apt-get install minicom |
213 |
Fedora, CentOS, RHEL, etc. | yum install minicom |
214 |
215 |
216 |
217 | On other Unix-like systems, you can try building
218 | minicom from source. On
219 | MacOS you can do that or try to install it from Fink. On Windows you're on
220 | your own; try RealTerm.
221 |
222 |
223 |
224 | Determine the name of the serial port you're using. On FreeBSD systems, USB
225 | serial adapters will have names like /dev/ttyU0
and hard-wired
226 | serial ports, /dev/ttyu0
with a lowercase 'u.' On Linux systems,
227 | the equivalent files are /dev/ttyUSB0
and
228 | /dev/ttyS0
, respectively. If you have more than one, the number
229 | might be greater than '0.' On Windows, it's usually called COM1
,
230 | otherwise COM2
, COM3
, and so on. On MacOS, it might
231 | be /dev/cu.usbserial
; look for other /dev/cu.*
232 | files if not.
233 |
234 |
235 |
236 | Configure the software to use the port, with settings 115200 8N1 and no flow
237 | control. Those are usually close to the defaults, but it's important to get
238 | them right as accidentally leaving flow control enabled or another error
239 | could leave you with a partially or not at all working connection. To
240 | configure minicom, enter the command minicom -s
as root, then
241 | navigate to the "Serial Port Setup" menu.
242 |
243 |
244 |
245 | Start the software and plug power into the device. You should see the EdgeOS
246 | Linux kernel boot and ultimately present you with a login prompt. If your
247 | device was already powered on, just hit the Enter key once or twice to get
248 | a new login prompt. Type something at the login prompt to verify that your
249 | connection is working properly. For example, you can log into EdgeOS (the
250 | default user and password are both ubnt
) and run the
251 | halt
command to shut it down and prepare for installing FreeBSD.
252 |
253 |
254 |
255 |
256 | Installation
257 |
258 |
259 |
260 | Unplug the device completely and open the plastic case by removing all the
261 | screws. Notice the lone USB port containing a removable drive on one end of
262 | the board. You can use your fingers to take the drive out, but it's a little
263 | slippery, so you might need to use your shirt for grip. It turns out there's
264 | a benefit to wearing shirts around the house, after all.
265 |
266 |
267 |
268 | Plug the drive into your computer. For FreeBSD, Linux and other Unix-like
269 | systems, the command to write the image to the drive is below. You'll need to
270 | download the xz
software
271 | for MacOS or if it's otherwise not installed. On Windows, which doesn't have
272 | dd
, you're on your own; try the
273 | Ubuntu Image Writer
274 | (you'll also have to download xz
).
275 |
276 |
277 |
278 | Determine the device name assigned by your system. On FreeBSD, it will be
279 | something like /dev/da3
, where the '3' will be the first
280 | available number after all your other SCSI and USB drives. On Linux,
281 | it will be something like /dev/sdf
, where the 'f' will be the
282 | first available letter after all your other ATA, SCSI and USB drives. On
283 | MacOS, it will be something like /dev/rdisk1
.
284 |
285 |
286 |
287 | Ensure it wasn't mounted automatically, by substituting your device name in
288 | the following commands and running them as root:
289 |
290 |
291 |
292 | mount | grep '^/dev/devicename' | awk '{print $1}' | xargs -n1 umount
293 | mount | grep '^/dev/devicename'
294 |
295 |
296 |
297 | If these commands produce no output, and you're certain you have the device
298 | name correct, proceed with the following command as root, substituting your
299 | device name and the filename of the image you downloaded or built.
300 |
301 | Warning: a simple typo in the device name can wipe out your system's boot
302 | partition. Check carefully before hitting the enter key.
303 |
304 |
305 |
306 | xzcat freebsd-ubiquiti-edgerouter-lite.debug.image.xz | dd of=/dev/devicename bs=1024k
307 |
308 |
309 |
310 | This will take a few minutes. When finished, remove the drive and put it back
311 | into the EdgeRouter Lite. Reconnect the console cable, ensure your terminal
312 | software is running, and plug power into the device.
313 |
314 |
315 |
316 | Configuring U-Boot
317 |
318 |
319 |
320 | The first time you power up the device with the new image, the bootloader
321 | won't know what to do and will drop you to a prompt. Enter these commands to
322 | save the command sequence needed to boot FreeBSD to a variable
323 | (boot_freebsd
in this example):
324 |
325 |
326 |
327 | setenv boot_freebsd 'fatload usb 0 $loadaddr kernel/kernel ; bootoctlinux $loadaddr coremask=0x3'
328 | saveenv
329 |
330 |
331 |
332 | You can now boot to FreeBSD simply by entering this command:
333 |
334 |
335 |
336 | run boot_freebsd
337 |
338 |
339 |
340 | Optionally, enter the following command to skip the pre-boot countdown.
341 | Personally, using minicom, I am still able to access the U-Boot console by
342 | sending a BREAK
at the first signs of life on the serial port, so
343 | I prefer not to have a delay. If you don't want to risk locking yourself
344 | out of the U-Boot console, skip this command or replace the 0
345 | with something like 3
(it's in seconds):
346 |
347 |
348 |
349 | setenv bootdelay 0
350 |
351 |
352 |
353 | Finally, to boot directly to FreeBSD by default, enter these commands:
354 |
355 |
356 |
357 | setenv bootcmd_orig $(bootcmd)
358 | setenv bootcmd 'run boot_freebsd'
359 | saveenv
360 | reset
361 |
362 |
363 |
364 |
365 | Growing the Filesystem
366 |
367 |
368 |
369 | At this point, you should be looking at a fully booted multi-user FreeBSD
370 | system. One of the first things you'll want to do is expand the filesystem to
371 | use all the free space left over on the drive after you wrote the relatively
372 | small image to it.
373 |
374 |
375 |
376 | Log in as root, then enter this command to bring the system to single-user
377 | mode:
378 |
379 |
380 |
381 | init 1
382 |
383 |
384 | Press ENTER
to accept the default shell, then enter the following
385 | commands:
386 |
387 |
388 | df -h /
389 | mount -o ro /
390 | gpart resize -i 2 da0
391 | gpart resize -i 1 da0s2
392 | growfs /dev/da0s2a
393 | df -h /
394 |
395 |
396 | You should be able to see much more available space in the second
397 | df
invocation. Enter the reboot
command to reboot
398 | back into multi-user mode.
399 |
400 |
401 | Success!
402 |
403 |
404 | Change the root password, edit the /etc/rc.conf
file to set up
405 | networking and services, and refer to
406 | The FreeBSD Handbook
407 | for system administration basics.
408 |
409 |
410 |
411 | Building Your Own
412 |
413 |
414 |
415 | -
416 | Update 2017/03/08:
device pf
and pflog
417 | added to default kernel config. Also available
418 |
419 | via git
with change history.
420 |
421 | -
422 | Update 2014/09/21: the latest version here fixes
423 | the problem of too few inodes, first spotted by Maximilian Präger.
424 |
425 |
426 |
427 | To build your own version from the FreeBSD sources, you will also need a
428 | computer running the same version of FreeBSD you wish to build. If your
429 | FreeBSD version is too old, a newer source tree's buildworld
may
430 | fail. I recommend first building, installing and booting the same version of
431 | the source on the build system as you plan to cross-build for the router.
432 | Refer to The FreeBSD
433 | Handbook for more information about obtaining FreeBSD sources, the
434 | buildworld
process and updating your FreeBSD system.
435 |
436 |
437 |
438 | Even if you use another OS, you can install FreeBSD inside a virtual machine,
439 | and use it to build a version of itself for your EdgeRouter Lite.
440 |
441 |
442 |
443 | The mkerlimage
script does everything
444 | needed to build the image from a fresh copy of the FreeBSD sources. It
445 | performs the following steps:
446 |
447 |
448 |
449 | - If
sys/mips/conf/ERL
doesn't exist, creates a simple one
450 | based on the OCTEON1
configuration.
451 |
452 | - Sets
TARGET=mips
and TARGET_ARCH=mips64
, then
453 | invokes buildworld
and buildkernel
to build the
454 | base system and kernel.
455 |
456 | - Invokes
installworld
and distribution
to
457 | install the newly built system to a temporary root.
458 |
459 | - Packages the whole thing up in a ~760MByte image, consisting of an MS-DOS
460 | partition for the kernel (so that U-Boot can read it), and a UFS fileystem
461 | for the rest. (Note that you can always grow the
462 | filesystem to the size of the media after installing and booting the
463 | image.)
464 |
465 |
466 |
467 | Please review the script before running it. In particular, make sure that
468 | you check the following:
469 |
470 |
471 |
472 | - The FreeBSD build system stores intermediate object files in
473 |
/usr/obj
by default. For the mips64 build, this will require
474 | at least 1.3GBytes of free space. Set the MAKEOBJDIRPREFIX
475 | environment variable if you want to put them somewhere else.
476 |
477 | - The script itself requires at least 2.0GBytes of temporary space to hold
478 | the installation root, UFS image, and final result image before compression.
479 | Check the
temp_root
setting at the top of the script, or it will
480 | all go to /tmp
by default.
481 |
482 | - Check that the number of jobs in the
make_args
setting at
483 | the top of the script is appropriate for your build machine.
484 |
485 |
486 |
487 | On success, you will have an xz
-compressed image, ready to
488 | decompress and dd
onto the destination. Follow the
489 | installation instructions, above.
490 |
491 |
492 |
493 | Contact
494 |
495 |
496 | The author of this page can be reached at
497 | erl@rtfm.net.
498 |
499 |
500 |
--------------------------------------------------------------------------------
/FreeBSD/ERL/mkerlimage:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | # Updated 2017 March 8, Nathan Dorfman
4 | # Based on the mkoctimage script from Warner Losh.
5 |
6 | # This script will build a FreeBSD image for the Ubiquiti EdgeRouter Lite.
7 | # More information is available at http://rtfm.net/FreeBSD/ERL/
8 |
9 | # After checking the following settings, run this script from the root of the
10 | # FreeBSD source tree you wish to build. You may also need to set the
11 | # MAKEOBJDIRPREFIX environment variable. See the FreeBSD Handbook for more
12 | # details about the FreeBSD build process.
13 |
14 | # Write the resulting image to a USB drive using:
15 | # xzcat "filename.image.gz" | dd of="/dev/devicename" bs=1024k
16 | # Boot it from the U-Boot prompt using:
17 | # fatload usb 0 $loadaddr kernel/kernel ; bootoctlinux $loadaddr coremask=0x3
18 |
19 | image_name=freebsd-ubiquiti-edgerouter-lite
20 |
21 | temp_root=$(mktemp -d) # 2GB+ of scratch space for temp root and UFS
22 | make_args='-DNO_CLEAN -j20' # any args to buildworld/buildkernel
23 | kern_conf=ERL # kernel config to use, or create if not there
24 | skip_build=false # true/false, don't run buildworld/buildkernel
25 | clean_up=true # true/false, delete temp root/UFS on success
26 | min_free_inodes=16384 # minimum # of free inodes left in new root fs
27 |
28 | #
29 | # The end.
30 | #
31 |
32 | set -e
33 |
34 | if [ ! -d sys/mips/conf ]; then
35 | echo $0: must be run from a FreeBSD source tree root > /dev/stderr
36 | exit 1
37 | fi
38 |
39 | kconffile=sys/mips/conf/$kern_conf
40 | kcompdir=sys/mips/compile/$kern_conf
41 | if [ ! -e ${kconffile} ]; then
42 | if [ -e ${kcompdir} ]; then
43 | echo $0: $kconffile does not exist but $kcompdir does. Check and\
44 | delete by hand, then run $0 again. > /dev/stderr
45 | exit 1
46 | fi
47 |
48 | echo
49 | echo $0: $kconffile not found, creating a new one based on OCTEON1
50 | echo
51 |
52 | (cd sys/mips/conf && sed -E -f/dev/stdin OCTEON1 << EOF > ${kern_conf}\
53 | && config ${kern_conf}) || exit 7
54 | s|^# OCTEON1.*|# ERL - EdgeRouter Lite kernel config, generated by mkerlimage, http://rtfm.net/FreeBSD/ERL|
55 | s/^ident[[:space:]].*/ident ERL/
56 | s/^(options[[:space:]]+ROOTDEVNAME=).*/\1\\\\"ufs:da0s2a\\\\" # Default root filesystem./
57 | s/^#(options[[:space:]]+OCTEON_VENDOR_UBIQUITI[[:space:]]*)/\1/
58 | s/^options[[:space:]]+([KDG]DB|DEADLKRES|MALLOC_DEBUG_.*)([[:space:]]*#.*)?/#&/
59 | s/^options[[:space:]]+(INVARIANTS?|WITNESS)(_[A-Z0-9_]+)?([[:space:]]*#.*)? /#&/
60 | s/^#(options[[:space:]]+OCTEON_MODEL=).*/\1OCTEON_CN50XX_PASS1/
61 | s/^options[[:space:]]+NO_SWAPPING([[:space:]]*#.*)?$/&\\
62 | options TMPFS # Temporary file system\\
63 | device pf\\
64 | device pflog/
65 | EOF
66 | fi
67 |
68 | rootdir=$temp_root/$image_name
69 |
70 | if cmp / $rootdir 2> /dev/null; then
71 | echo $0: something went horribly wrong, check script settings > /dev/stderr
72 | exit 255
73 | fi
74 |
75 | export TARGET=mips
76 | export TARGET_ARCH=mips64
77 |
78 | if ${skip_build}; then
79 | echo $0: skipping buildworld and buildkernel steps
80 | else
81 | make buildworld ${make_args} || exit 2
82 | make buildkernel ${make_args} KERNCONF=${kern_conf} || exit 3
83 | fi
84 |
85 | mkdir -p ${rootdir}
86 | make installworld DESTDIR=${rootdir} || exit 4
87 | make distribution DESTDIR=${rootdir} || exit 5
88 | make installkernel KERNCONF=${kern_conf} DESTDIR=${rootdir} || exit 6
89 |
90 | cat < ${rootdir}/etc/fstab
91 | # Device Mountpoint FStype Options Dump Pass#
92 | /dev/da0s2a / ufs rw 1 1
93 | /dev/da0s1 /uboot msdosfs rw 0 0
94 | tmpfs /tmp tmpfs rw,mode=1777,size=192m 0 0
95 | EOF
96 |
97 | cat < ${rootdir}/etc/rc.conf
98 | hostname=erl
99 | ifconfig_octe0="DHCP"
100 | #ifconfig_octe1="inet 10.11.12.13/24"
101 | #ifconfig_octe2="inet 10.9.8.7/24"
102 | #gateway_enable="YES"
103 | #sshd_enable="YES"
104 | #ntpd_enable="YES"
105 | #ntpd_sync_on_start="YES"
106 | EOF
107 |
108 | cat <> ${rootdir}/etc/motd
109 | Image built with mkerlimage, http://rtfm.net/FreeBSD/ERL
110 |
111 | EOF
112 |
113 | # 3800MiB is just shy of 4GB in bytes
114 | IMG_SIZE=$((3800 * 1024 * 1024))
115 | DOS_SECTORS=$(( (3800 - 3600) * 1024 * 2))
116 |
117 | cp /dev/null ${rootdir}.image
118 | dd if=/dev/zero of=${rootdir}.image oseek=${IMG_SIZE} bs=1 count=0
119 | md=$(mdconfig -f ${rootdir}.image)
120 | gpart create -s mbr ${md}
121 | gpart add -t !6 -s ${DOS_SECTORS} ${md}
122 | gpart add -t freebsd ${md}
123 | gpart create -s BSD ${md}s2
124 | gpart add -b 16 -t freebsd-ufs ${md}s2
125 |
126 | newfs_msdos -F 16 /dev/${md}s1
127 | mount -t msdosfs /dev/${md}s1 /mnt
128 | cp ${rootdir}/boot/kernel/kernel /mnt
129 | umount /mnt
130 |
131 | mkdir ${rootdir}/uboot
132 | makefs -f ${min_free_inodes} -B big -s 3600m ${rootdir}.ufs ${rootdir}
133 | dd if=${rootdir}.ufs of=/dev/${md}s2a bs=1m || true
134 |
135 | mdconfig -d -u ${md}
136 | xz -9f ${rootdir}.image
137 | echo ${rootdir}.image.xz successfully created!
138 |
139 | if $clean_up; then
140 | chflags -R noschg ${rootdir}
141 | rm -rf ${rootdir}.ufs ${rootdir}
142 | fi
143 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright © 2020 Nathan Dorfman
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/scripts/check_spf_rules.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl -w
2 | # Copyright 2015 Nathan Dorfman
3 | #
4 | # Checks whether hosts are allowed by domains' SPF policies.
5 | # Expected results go to STDOUT and others to STDERR for easy filtering.
6 | # Specify hosts expected to pass with -h, or fail with -b.
7 | # Use -b without host to check a default, illegal one.
8 | # Use -p to read the relay host from a Postfix config file.
9 | #
10 | # Examples:
11 | # ./check_spf_rules.pl -b known.spammer.net my.domain my.domain2 ...
12 | # (check that spammer is blocked)
13 | # ./check_spf_rules.pl -b -h `hostname` my.domain my.domain2 ...
14 | # (check that we are allowed, and that default is blocked)
15 | # ./check_spf_rules.pl -p /etc/mail/postmail.cf my.domain my.domain2 ...
16 | # (check that postfix relayhost is allowed. instead of optional
17 | # filename, another option or -- may follow to use this default)
18 | # ./check_spf_rules.pl -p -h gmail.com my.domain my.domain2 ...
19 | # (check that postfix relayhost and favorite forwarder are allowed)
20 | #
21 | # Example crontab:
22 | # mm hh dd * * check_spf_rules.pl -b -p -- $MY_DOMAINS > /dev/null
23 |
24 | use Mail::SPF;
25 | use Socket;
26 | use Getopt::Long;
27 | use strict;
28 |
29 | {
30 | my (@good, @bad);
31 |
32 | GetOptions(
33 | "host=s" => \@good,
34 | "badhost:s@" => \@bad,
35 | "postfixcf:s" => sub { push @good, get_postfix_relayhost($_[1]) }
36 | );
37 |
38 | die "Usage: $0 -p | -h [-r ... ] domains...\n"
39 | unless @ARGV && (@good || @bad);
40 |
41 | my $spf = Mail::SPF::Server->new();
42 |
43 | for my $domain (@ARGV) {
44 | for my $host (@good) {
45 | check_host_domain($spf, $host, $domain, 'pass');
46 | }
47 | for my $host (@bad) {
48 | $host = '192.168.1.1' unless $host;
49 | check_host_domain($spf, $host, $domain, 'softfail', 'fail');
50 | }
51 | }
52 | }
53 |
54 | sub get_postfix_relayhost {
55 | my $file = ($_[0] || '/etc/postfix/main.cf');
56 | my $result;
57 |
58 | open(my $FH, $file) || die "failed to read postfix config file '$file'\n";
59 | while(<$FH>) {
60 | if (/^relayhost\s*=\s*(\[?)(.*)(?(1)\]|)\s*$/) {
61 | $result = (defined $result) ? undef : $2;
62 | }
63 | }
64 | close $FH;
65 |
66 | die "failed to read relayhost directive from postfix config file '$file'\n"
67 | unless defined $result;
68 |
69 | return $result;
70 | }
71 |
72 | sub check_host_domain {
73 | my ($spf, $host, $domain, @x) = @_;
74 |
75 | my $addr = gethostbyname $host;
76 | unless (defined $addr) {
77 | print STDERR "$host not found\n";
78 | return;
79 | }
80 |
81 | my $result = $spf->process(Mail::SPF::Request->new(
82 | scope => 'mfrom',
83 | identity => 'user@' . $domain,
84 | ip_address => inet_ntoa($addr)
85 | ));
86 |
87 | my $o = grep($result->is_code($_), @x) ? *STDOUT : *STDERR;
88 | print $o "$domain from $host: $result\n";
89 | }
90 |
--------------------------------------------------------------------------------
/scripts/docker-apt-proxy.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | # Copyright © 2019 Nathan Dorfman
3 |
4 | case "$1" in
5 | --pull|-p)
6 | shift
7 | docker pull "$1" || exit 2
8 | ;;
9 | esac
10 |
11 | if [ "$#" -gt 2 -o "$#" -lt 1 -o "${1#-}" != "$1" ]; then
12 | echo "Usage: $0 [--pull|-p] [http://:/...]" >&2
13 | exit 1
14 | elif [ "$#" -gt 1 ]; then
15 | proxy_url="$2"
16 | else
17 | proxy_url='http://172.17.0.1:3142/'
18 | fi
19 |
20 | set -e
21 | temp_dir=$(mktemp -d)
22 | cd "$temp_dir"
23 |
24 | cat > Dockerfile << EOF
25 | FROM $1
26 |
27 | RUN echo "Acquire::http::Proxy \"${proxy_url}\";" > /etc/apt/apt.conf.d/99proxy
28 | EOF
29 |
30 | docker build --tag "$1" .
31 |
32 | echo Created "$1" using apt proxy "$proxy_url".
33 | cd || cd /
34 | rm "$temp_dir"/Dockerfile
35 | rmdir "$temp_dir"
36 |
--------------------------------------------------------------------------------
/scripts/file_holes.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | # Copyright 2018 Nathan Dorfman
3 | #
4 | # Checks whether specified files (or stdin by default) have holes in them.
5 | # Unless the -q option is given, prints every hole found on stdout and every
6 | # file without holes on stderr.
7 | # Exit value is number of files in which holes were NOT found.
8 |
9 | use strict;
10 | use warnings;
11 |
12 | # Check an open file handle for holes using SEEK_HOLE.
13 | # In scalar context, returns a true value if at least one hole exists and a
14 | # false one otherwise.
15 | # In list context, returns a list containing of holes, each represented by a
16 | # reference to a two-element array like [ OFFSET, LENGTH ].
17 |
18 | sub check_handle_impl {
19 | my $fh = shift || die 'filehandle required';
20 | my $quick = !wantarray;
21 |
22 | use Fcntl qw(:seek);
23 | use constant SEEK_DATA => 3;
24 | use constant SEEK_HOLE => 4;
25 |
26 | seek($fh, 0, SEEK_END) || die "SEEK_END failed: $!";
27 | my $end = tell $fh;
28 | my $cur = 0;
29 | my $holes = $quick ? undef : [];
30 | while ($cur < $end) {
31 | seek($fh, $cur, SEEK_HOLE) || die "SEEK_HOLE failed: $!";
32 | my $hole = tell $fh;
33 | last if $hole == $end;
34 | return 1 if $quick;
35 |
36 | $cur = seek($fh, $hole, SEEK_DATA) ? tell $fh : $end;
37 |
38 | push @$holes, [ $hole, $cur - $hole ];
39 | }
40 |
41 | return $quick ? 0 : @$holes;
42 | }
43 |
44 | sub check_handle {
45 | my ($name, $handle, $quiet) = @_;
46 | return check_handle_impl($handle) if $quiet;
47 |
48 | my @holes = check_handle_impl($handle);
49 | if (@holes) {
50 | for (@holes) {
51 | printf "%s: %d-byte hole at offset %d\n", $name, $_->[1], $_->[0];
52 | }
53 | return scalar @holes;
54 | }
55 |
56 | print STDERR "$name doesn't have any holes.\n";
57 | return 0;
58 | }
59 |
60 | sub check_files {
61 | my $quiet = shift;
62 | my $count = 0;
63 | for (@_) {
64 | open(HANDLE, '<', $_) || die "$_: $!";
65 | eval { ++$count if !check_handle($_, *HANDLE, $quiet) };
66 | die "$_: $@" if $@;
67 | close HANDLE;
68 | }
69 | return $count;
70 | }
71 |
72 | use constant QUIET => (@ARGV && $ARGV[0] eq '-q') ? shift : 0;
73 | exit(@ARGV ? check_files(QUIET, @ARGV) : !check_handle('', *STDIN));
74 |
--------------------------------------------------------------------------------
/scripts/harp.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | # Copyright 2020 Nathan Dorfman
3 | #
4 | # Decorates /proc/net/arp entries with DNS names.
5 | #
6 | # Usage: harp.pl [filename...]
7 | #
8 | # Optionally specify one or more files to read from instead of /proc/net/arp.
9 | # To read from stdin, specify '-'.
10 | #
11 |
12 | use strict;
13 | use warnings;
14 |
15 | use Socket;
16 |
17 | if (!@ARGV) {
18 | use constant DEFAULT_FILE => '/proc/net/arp';
19 | open STDIN, DEFAULT_FILE || die DEFAULT_FILE . ": $!\n";
20 | }
21 |
22 | while (<>) {
23 | chomp;
24 | next if $_ eq 'IP address HW type Flags HW address Mask Device';
25 |
26 | my ($ip, undef, undef, $eth, undef) = split;
27 | my $res = gethostbyaddr(inet_aton($ip), AF_INET);
28 | $res = '-' unless defined $res;
29 |
30 | printf "%-15s [%s] %s\n", $ip, $eth, $res;
31 | }
32 |
--------------------------------------------------------------------------------
/scripts/lart.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 | # Copyright 2018 Nathan Dorfman
3 | #
4 | # Sorts filenames by mtime, for when you have too many for `xargs | ls -rt.'
5 | #
6 | # Usage: lart.pl [ --null | -0 ] [ --long | -l ] [ ]
7 | # Options:
8 | # -0, --null Delimiter is '\0' instead of '\n'
9 | # -l, --long Print timestamps along with filenames
10 | #
11 | # If any are specified, the list of filenames to sort is read from
12 | # therein; otherwise stdin.
13 | #
14 | # Example: find / -type f | lart.pl
15 | #
16 |
17 | use strict;
18 | use warnings;
19 |
20 | use File::stat;
21 | use Getopt::Long;
22 |
23 | package SortedList;
24 |
25 | sub new {
26 | my $type = shift;
27 | my $cmp = (shift || sub { $_[0] cmp $_[1] });
28 |
29 | bless { cmp => $cmp, data => [] }, $type;
30 | }
31 |
32 | sub data { $_[0]->{data} }
33 |
34 | sub insert {
35 | my $self = shift;
36 | my $new_data = shift;
37 | my $cmp = $self->{cmp};
38 | my $data = $self->{data};
39 | my $end = $#$data;
40 |
41 | if (!@$data || &$cmp($new_data, $$data[$end]) >= 0) {
42 | push @$data, $new_data;
43 | return;
44 | }
45 |
46 | my $idx = 0;
47 | my $begin = 0;
48 |
49 | for (;;) {
50 | if (&$cmp($new_data, $$data[$idx]) < 0) {
51 | last if $idx == $begin || &$cmp($new_data, $$data[$idx - 1]) >= 0;
52 | $end = $idx;
53 | }
54 | else {
55 | $begin = $idx + 1;
56 | }
57 | $idx = int(($begin + $end) / 2)
58 | }
59 |
60 | splice @$data, $idx, 0, $new_data;
61 | }
62 |
63 | package main;
64 |
65 | my $long_output;
66 | GetOptions('0|null' => sub { $/ = "\0" },
67 | 'l|long' => \$long_output);
68 |
69 | my $files = new SortedList(
70 | sub {
71 | $_[0]->[1]->mtime <=> $_[1]->[1]->mtime;
72 | }
73 | );
74 |
75 | while(<>) {
76 | chomp;
77 | my $stat = stat $_;
78 | $stat ? $files->insert([ $_, $stat ])
79 | : warn "$_: $!\n";
80 | }
81 |
82 | for (@{$files->data}) {
83 | print scalar localtime $_->[1]->mtime, ': ' if $long_output;
84 | print $_->[0], $/;
85 | }
86 |
--------------------------------------------------------------------------------