├── 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 | 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 |
  1. 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 |
  2. There is currently no way to pass boot options (such as single-user mode) 84 | to the kernel from U-Boot.
  3. 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 |

Image Files

93 | 94 | 95 | 96 | 97 | 102 | 103 | 104 | 105 | 111 | 112 | 113 | 114 | 116 | 117 | 119 |
2017/03/07FreeBSD 11.0-RELEASE-p8-r314813 99 | 100 | SHA512
2014/11/19FreeBSD 10.1-RELEASE-r274683 107 | 108 | 109 | SHA512
2014/01/24FreeBSD 10.0-RELEASE r261039SHA512
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 |
  1. a computer with a USB port
  2. 138 | 139 |
  3. 140 | the device
  4. 141 | 142 |
  5. 143 | an RJ-45 serial console cable
  6. 144 | 145 |
  7. 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 |
  8. a Phillips-head screwdriver.
  9. 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 | 210 | 211 | 212 | 213 | 214 |
System Command
FreeBSD 10.0+ pkg install minicom
FreeBSD 9.x pkg_add -r minicom
Debian, Ubuntu, Mint, etc. apt-get install minicom
Fedora, CentOS, RHEL, etc. yum install minicom
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 | 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 |
  1. If sys/mips/conf/ERL doesn't exist, creates a simple one 450 | based on the OCTEON1 configuration.
  2. 451 | 452 |
  3. Sets TARGET=mips and TARGET_ARCH=mips64, then 453 | invokes buildworld and buildkernel to build the 454 | base system and kernel.
  4. 455 | 456 |
  5. Invokes installworld and distribution to 457 | install the newly built system to a temporary root.
  6. 458 | 459 |
  7. 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.)
  8. 464 |
465 | 466 |

467 | Please review the script before running it. In particular, make sure that 468 | you check the following: 469 |

470 | 471 | 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 | --------------------------------------------------------------------------------