Initial commit
This commit is contained in:
commit
2034e94d7e
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
*.html
|
198
algorithm-roll.org
Normal file
198
algorithm-roll.org
Normal file
File diff suppressed because one or more lines are too long
BIN
algorithm-roll/tlakh.xyz-2020-06-08-16_52_00-UTC.png
Normal file
BIN
algorithm-roll/tlakh.xyz-2020-06-08-16_52_00-UTC.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
BIN
algorithm-roll/tlakh.xyz-2020-06-09-16_55_33-UTC.png
Normal file
BIN
algorithm-roll/tlakh.xyz-2020-06-09-16_55_33-UTC.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 111 KiB |
BIN
algorithm-roll/tlakh.xyz-2020-06-11-06_10_11-UTC.png
Normal file
BIN
algorithm-roll/tlakh.xyz-2020-06-11-06_10_11-UTC.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
BIN
algorithm-roll/tlakh.xyz-2020-06-11-08_04_42-UTC.png
Normal file
BIN
algorithm-roll/tlakh.xyz-2020-06-11-08_04_42-UTC.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 110 KiB |
BIN
algorithm-roll/tlakh.xyz-2020-06-12-08_18_08-UTC.png
Normal file
BIN
algorithm-roll/tlakh.xyz-2020-06-12-08_18_08-UTC.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 96 KiB |
368
fuzzing-ping.org
Normal file
368
fuzzing-ping.org
Normal file
@ -0,0 +1,368 @@
|
|||||||
|
#+TITLE: Fuzzing ping(8)
|
||||||
|
#+SUBTITLE: ... and finding a 24 year old bug.
|
||||||
|
#+DATE: 2022-12-01
|
||||||
|
* Prologue
|
||||||
|
[[https://freebsd.org][FreeBSD]] had a [[https://www.freebsd.org/security/advisories/FreeBSD-SA-22:15.ping.asc][security fluctuation]] in their implementation of =ping(8)=
|
||||||
|
the other day. As someone who has done a lot of work on [[https://man.openbsd.org/man/ping.8][=ping(8)=]] in
|
||||||
|
[[https://openbsd.org][OpenBSD]] this tickled my interests.
|
||||||
|
* What about OpenBSD?
|
||||||
|
=ping(8)= is ancient:
|
||||||
|
#+begin_example
|
||||||
|
* Author -
|
||||||
|
* Mike Muuss
|
||||||
|
* U. S. Army Ballistic Research Laboratory
|
||||||
|
* December, 1983
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
What we know today as =ping(8)= started to become recognizable in 1986, for
|
||||||
|
example see this [[https://github.com/csrg/csrg/commit/962056110ebf62ed8d4368964c7e82ac7434ea82][csrg commit]].
|
||||||
|
|
||||||
|
FreeBSD identified a stack overflow in the =pr_pack()= function and I
|
||||||
|
expected a lot of similarity between the BSDs. This stuff did not
|
||||||
|
change a lot since the csrg days.
|
||||||
|
|
||||||
|
Step one: Does this effect us? Turns out, it does not. FreeBSD rewrote
|
||||||
|
=pr_pack()= in [[https://github.com/freebsd/freebsd-src/commit/d9cacf605e2ac0f704e1ce76357cbfbe6cb63d52][2019]], citing alignment problems.
|
||||||
|
|
||||||
|
Now we could join the punters on the Internet and point and laugh. But
|
||||||
|
that's just rude, uncalled for, and generally boring and
|
||||||
|
pointless. Technically I'm on vacation and I had resolved to only do
|
||||||
|
fun things this week. So let's have some fun.
|
||||||
|
|
||||||
|
Step two: FreeBSD had a problem in =pr_pack()= because that function
|
||||||
|
handles data from the network. The data is untrusted and needs to be
|
||||||
|
validated. Now is a good time as any to check OpenBSD's implementation
|
||||||
|
of =pr_pack()=. I wanted to try fuzzing something, anything, with [[https://en.wikipedia.org/wiki/American_fuzzy_lop_(fuzzer)][afl]]
|
||||||
|
for a few years, but never got around to it. I thought I might as well
|
||||||
|
do it now, might be fun.
|
||||||
|
|
||||||
|
* Make sure you are not holding it wrong.
|
||||||
|
I installed =afl++= from packages and glanced at "[[https://aflplus.plus/docs/tutorials/libxml2_tutorial/][Fuzzing libxml2 with
|
||||||
|
AFL++]]".
|
||||||
|
Here is what we need:
|
||||||
|
+ A program to test. Something with a know bug so that we can tell the
|
||||||
|
fuzzing works.
|
||||||
|
+ A file as input, that does not trigger the bug.
|
||||||
|
+ Compile the program with =afl-clang-fast=.
|
||||||
|
+ Run =afl-fuzz=.
|
||||||
|
|
||||||
|
=test.c:=
|
||||||
|
#+begin_src C
|
||||||
|
/* Written by Florian Obser, Public Domain */
|
||||||
|
#include <err.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
size_t fsize;
|
||||||
|
uint8_t *buf, len, *dbuf;
|
||||||
|
|
||||||
|
f = fopen(argv[1], "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
fsize = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
buf = malloc(fsize + 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
err(1, NULL);
|
||||||
|
fread(buf, fsize, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
buf[fsize] = 0;
|
||||||
|
|
||||||
|
len = buf[0];
|
||||||
|
|
||||||
|
dbuf = malloc(len);
|
||||||
|
if (dbuf == NULL)
|
||||||
|
err(1, NULL);
|
||||||
|
memcpy(buf + 1, dbuf, fsize - 1);
|
||||||
|
warnx("len: %d", len);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
This program has a trivial buffer overflow. It figures out how big a
|
||||||
|
file is on disk and stores this in =fsize=. Then it goes ahead and
|
||||||
|
reads the whole file into a buffer. It interprets the first byte as
|
||||||
|
the length of data (=len=) and allocates a new buffer (=dbuf=) of this
|
||||||
|
size. It skips the length byte and copies =fsize - 1= bytes into the
|
||||||
|
new buffer. So it trusts that the amount of data it read from disk is
|
||||||
|
the same as indicated by the length byte.
|
||||||
|
|
||||||
|
While this might seem silly, this is how real world buffer overflows
|
||||||
|
look like.
|
||||||
|
|
||||||
|
Here is a file where the length byte and file size agree. Create
|
||||||
|
folders =in= and =out= and place =test.txt= into =in/test.txt=. Don't
|
||||||
|
forget the newline.
|
||||||
|
|
||||||
|
=test.txt=:
|
||||||
|
#+begin_example
|
||||||
|
ABBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
|
||||||
|
#+end_example
|
||||||
|
|
||||||
|
Compile =test.c=:
|
||||||
|
#+begin_src shell
|
||||||
|
CC=/usr/local/bin/afl-clang-fast make test
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
and run =afl-fuzz=:
|
||||||
|
#+begin_src shell
|
||||||
|
afl-fuzz -i in/ -o out -- ./test @@
|
||||||
|
#+end_src
|
||||||
|
It more or less immediately finds a crash. The reproducer(s) are in
|
||||||
|
=out/default/crashes/=.
|
||||||
|
* Fuzzing =ping(8)=
|
||||||
|
At this point we are facing a few problems. What does it mean to fuzz
|
||||||
|
=ping(8)=, where are we getting the sample input from and how do we feed
|
||||||
|
it to =ping(8)=.
|
||||||
|
|
||||||
|
From a high level point of view =ping(8)= parses arguments, initializes
|
||||||
|
a bunch of stuff and then enters an infinite loop sending ICMP echo
|
||||||
|
packets and waiting for a reply. It then parses and prints the reply.
|
||||||
|
|
||||||
|
Parsing the reply is the interesting thing. The reply comes from the
|
||||||
|
network and is untrusted. This is where things go wrong. The parsing
|
||||||
|
is handled by =pr_pack()=, so that's what we should fuzz.
|
||||||
|
|
||||||
|
** =in/= for =ping(8)=
|
||||||
|
Now we need sample data. An ICMP package is binary data
|
||||||
|
on-wire. Crafting it by hand is annoying. So let's just hack =ping(8)=
|
||||||
|
to dump the packet to disk.
|
||||||
|
#+begin_src diff
|
||||||
|
diff --git sbin/ping/ping.c sbin/ping/ping.c
|
||||||
|
index a3b3d650eb5..78b571b95b4 100644
|
||||||
|
--- sbin/ping/ping.c
|
||||||
|
+++ sbin/ping/ping.c
|
||||||
|
@@ -79,6 +79,7 @@
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
+#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
@@ -95,6 +96,7 @@
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
+#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <poll.h>
|
||||||
|
@@ -217,6 +219,8 @@ const char *pr_addr(struct sockaddr *, socklen_t);
|
||||||
|
void pr_pack(u_char *, int, struct msghdr *);
|
||||||
|
__dead void usage(void);
|
||||||
|
|
||||||
|
+void output(char *, u_char *, int);
|
||||||
|
+
|
||||||
|
/* IPv4 specific functions */
|
||||||
|
void pr_ipopt(int, u_char *);
|
||||||
|
int in_cksum(u_short *, int);
|
||||||
|
@@ -255,7 +259,7 @@ main(int argc, char *argv[])
|
||||||
|
int df = 0, tos = 0, bufspace = IP_MAXPACKET, hoplimit = -1, mflag = 0;
|
||||||
|
u_char *datap, *packet;
|
||||||
|
u_char ttl = MAXTTL;
|
||||||
|
- char *e, *target, hbuf[NI_MAXHOST], *source = NULL;
|
||||||
|
+ char *e, *target, hbuf[NI_MAXHOST], *source = NULL, *output_path = NULL;
|
||||||
|
char rspace[3 + 4 * NROUTES + 1]; /* record route space */
|
||||||
|
const char *errstr;
|
||||||
|
double fraction, integral, seconds;
|
||||||
|
@@ -264,11 +268,13 @@ main(int argc, char *argv[])
|
||||||
|
u_int rtableid = 0;
|
||||||
|
extern char *__progname;
|
||||||
|
|
||||||
|
+#if 0
|
||||||
|
/* Cannot pledge due to special setsockopt()s below */
|
||||||
|
if (unveil("/", "r") == -1)
|
||||||
|
err(1, "unveil /");
|
||||||
|
if (unveil(NULL, NULL) == -1)
|
||||||
|
err(1, "unveil");
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
if (strcmp("ping6", __progname) == 0) {
|
||||||
|
v6flag = 1;
|
||||||
|
@@ -297,8 +303,8 @@ main(int argc, char *argv[])
|
||||||
|
preload = 0;
|
||||||
|
datap = &outpack[ECHOLEN + ECHOTMLEN];
|
||||||
|
while ((ch = getopt(argc, argv, v6flag ?
|
||||||
|
- "c:DdEefgHh:I:i:Ll:mNnp:qS:s:T:V:vw:" :
|
||||||
|
- "DEI:LRS:c:defgHi:l:np:qs:T:t:V:vw:")) != -1) {
|
||||||
|
+ "c:DdEefgHh:I:i:Ll:mNno:p:qS:s:T:V:vw:" :
|
||||||
|
+ "DEI:LRS:c:defgHi:l:no:p:qs:T:t:V:vw:")) != -1) {
|
||||||
|
switch(ch) {
|
||||||
|
case 'c':
|
||||||
|
npackets = strtonum(optarg, 0, INT64_MAX, &errstr);
|
||||||
|
@@ -375,6 +381,9 @@ main(int argc, char *argv[])
|
||||||
|
case 'n':
|
||||||
|
options &= ~F_HOSTNAME;
|
||||||
|
break;
|
||||||
|
+ case 'o':
|
||||||
|
+ output_path = optarg;
|
||||||
|
+ break;
|
||||||
|
case 'p': /* fill buffer with user pattern */
|
||||||
|
options |= F_PINGFILLED;
|
||||||
|
fill((char *)datap, optarg);
|
||||||
|
@@ -768,10 +777,10 @@ main(int argc, char *argv[])
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & F_HOSTNAME) {
|
||||||
|
- if (pledge("stdio inet dns", NULL) == -1)
|
||||||
|
+ if (pledge("stdio inet dns wpath cpath", NULL) == -1)
|
||||||
|
err(1, "pledge");
|
||||||
|
} else {
|
||||||
|
- if (pledge("stdio inet", NULL) == -1)
|
||||||
|
+ if (pledge("stdio inet wpath cpath", NULL) == -1)
|
||||||
|
err(1, "pledge");
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -960,8 +969,11 @@ main(int argc, char *argv[])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
- } else
|
||||||
|
+ } else {
|
||||||
|
+ if (output_path != NULL)
|
||||||
|
+ output(output_path, packet, cc);
|
||||||
|
pr_pack(packet, cc, &m);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (npackets && nreceived >= npackets)
|
||||||
|
break;
|
||||||
|
@@ -2274,3 +2286,29 @@ usage(void)
|
||||||
|
}
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+output(char *path, u_char *pack, int len)
|
||||||
|
+{
|
||||||
|
+ size_t bsz, off;
|
||||||
|
+ ssize_t nw;
|
||||||
|
+ int fd;
|
||||||
|
+ char *fname;
|
||||||
|
+
|
||||||
|
+ bsz = len;
|
||||||
|
+ if (asprintf(&fname, "%s/ping_%lld_%d.out", path, time(NULL),
|
||||||
|
+ getpid()) == -1)
|
||||||
|
+ err(1, NULL);
|
||||||
|
+
|
||||||
|
+ fd = open(fname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP |
|
||||||
|
+ S_IROTH);
|
||||||
|
+ free(fname);
|
||||||
|
+
|
||||||
|
+ if (fd == -1)
|
||||||
|
+ err(1, "open");
|
||||||
|
+
|
||||||
|
+ for (off = 0; off < bsz; off += nw)
|
||||||
|
+ if ((nw = write(fd, pack + off, bsz - off)) == 0 || nw == -1)
|
||||||
|
+ err(1, "write");
|
||||||
|
+ close(fd);
|
||||||
|
+}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
After building and installing our hacked version of =ping(8)= we can
|
||||||
|
create sample input data for afl thusly:
|
||||||
|
#+begin_src shell
|
||||||
|
while :; do
|
||||||
|
ping -o ./in/ -w 1 -c 1 \
|
||||||
|
$(jot -r 0 255 | head -4 | tr '\n' '.' | sed 's/.$//')
|
||||||
|
done
|
||||||
|
#+end_src
|
||||||
|
=jot= creates a stream of random numbers between 0 and 255, we get the
|
||||||
|
first four, concatenate them with '.' and cut of the trailing
|
||||||
|
dot. Voilà we have a bunch of random IPv4 addresses. We then send a
|
||||||
|
single ping and wait for one second. The ICMP reply is written to
|
||||||
|
=./in/=.
|
||||||
|
|
||||||
|
** Fuzzing =pr_pack()=
|
||||||
|
At this point I wrote a =main()= function that accepts a file name as
|
||||||
|
argument, and reads it into a buffer. I then ripped =pr_pack()= out of
|
||||||
|
=ping(8)= and fed it the file contents.
|
||||||
|
|
||||||
|
Of course compiling fails quite spectacularly at this point. So I
|
||||||
|
added a bunch of missing functions, defines and global variables. It
|
||||||
|
gets pretty close now. We don't have the =msghdr= from =recvfrom(2)= so
|
||||||
|
we need to =#if 0= some code. We also need to get rid of the
|
||||||
|
validation of the data packet using =SipHash= because the whole point
|
||||||
|
is that the data does not validate and =SipHash= would short circuit.
|
||||||
|
|
||||||
|
Oh yeah, and the thing is legacy IP only at this point.
|
||||||
|
|
||||||
|
So [[file:fuzzing-ping/afl_ping.c][here (=afl_ping.c=)]] it is, it is quite terrible. It would probably make more sense
|
||||||
|
to copy all of =ping(8)= and slap on a new =main()= function. Maybe.
|
||||||
|
|
||||||
|
Anyway, at this point I was 30 minutes in, from reading about afl for
|
||||||
|
the first time until firing up =afl-fuzz= on my hacked
|
||||||
|
=pr_pack()=. Not too bad. It was now time for dinner and I left the
|
||||||
|
thing running.
|
||||||
|
|
||||||
|
** The promised bug
|
||||||
|
I came back after dinner and afl found zero crashes. That's
|
||||||
|
disappointing. Or good. Depending on how you look at it. But it found
|
||||||
|
hangs. Running =afl_ping= on one of the reproducers, it printed
|
||||||
|
=unknown option 20= forever.
|
||||||
|
|
||||||
|
The problem is in this part of the code:
|
||||||
|
#+begin_src C
|
||||||
|
for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) {
|
||||||
|
/* [...] */
|
||||||
|
switch (*cp) {
|
||||||
|
/* [...] */
|
||||||
|
default:
|
||||||
|
printf("\nunknown option %x", *cp);
|
||||||
|
hlen = hlen - (cp[IPOPT_OLEN] - 1);
|
||||||
|
cp = cp + (cp[IPOPT_OLEN] - 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
=cp= is untrusted data and if =cp[IPOPT_OLEN]= is zero we would
|
||||||
|
increase =hlen= by one and the for loop would subtract one, same for
|
||||||
|
=cp=. We never make any progress and spin forever.
|
||||||
|
|
||||||
|
The diff is fairly simple:
|
||||||
|
#+begin_src diff
|
||||||
|
diff --git ping.c ping.c
|
||||||
|
index fb31365ad31..6019c87d8db 100644
|
||||||
|
--- ping.c
|
||||||
|
+++ ping.c
|
||||||
|
@@ -1525,8 +1525,11 @@ pr_ipopt(int hlen, u_char *buf)
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\nunknown option %x", *cp);
|
||||||
|
- hlen = hlen - (cp[IPOPT_OLEN] - 1);
|
||||||
|
- cp = cp + (cp[IPOPT_OLEN] - 1);
|
||||||
|
+ if (cp[IPOPT_OLEN] > 0 && (cp[IPOPT_OLEN] - 1) <= hlen) {
|
||||||
|
+ hlen = hlen - (cp[IPOPT_OLEN] - 1);
|
||||||
|
+ cp = cp + (cp[IPOPT_OLEN] - 1);
|
||||||
|
+ } else
|
||||||
|
+ hlen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#+end_src
|
||||||
|
|
||||||
|
I foolishly tweaked the diff after collecting OKs and of course the
|
||||||
|
tweak was wrong. Note to self: Never do this. So it's spread out over
|
||||||
|
two commits: [[https://cvsweb.openbsd.org/src/sbin/ping/ping.c#rev1.247][ping.c, Revision 1.247]] and [[https://cvsweb.openbsd.org/src/sbin/ping/ping.c#rev1.248][ping.c, Revision 1.248]].
|
||||||
|
|
||||||
|
This bug was introduced April 3rd, 1998 in [[https://cvsweb.openbsd.org/src/sbin/ping/ping.c#rev1.30][revision 1.30]], over 24
|
||||||
|
years ago.
|
||||||
|
|
||||||
|
* Epilogue
|
||||||
|
Afl uses files to feed data to programs to get them to crash or
|
||||||
|
otherwise misbehave. I had wondered for a few years how I could use
|
||||||
|
afl with things that talk to the network. Because that's what I mostly
|
||||||
|
work on. In hindsight it's quite obvious. You identify the main
|
||||||
|
parsing function, wrap it in a new =main()= function and Robert is
|
||||||
|
your father's nearest male relative.
|
||||||
|
|
||||||
|
The two main takeaways from this are: One, if someone messes up
|
||||||
|
somewhere, go look if you messed up in the same or similar way
|
||||||
|
somewhere else. Two, afl is pretty easy to use, even for network
|
||||||
|
programs. 30 minutes from reading about afl for the first time to
|
||||||
|
finding a bug in a real world program is pretty neat.
|
892
fuzzing-ping/afl_ping.c
Normal file
892
fuzzing-ping/afl_ping.c
Normal file
@ -0,0 +1,892 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the project nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright (c) 1989, 1993
|
||||||
|
* The Regents of the University of California. All rights reserved.
|
||||||
|
*
|
||||||
|
* This code is derived from software contributed to Berkeley by
|
||||||
|
* Mike Muuss.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* 1. Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. Neither the name of the University nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||||
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||||
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Using the InterNet Control Message Protocol (ICMP) "ECHO" facility,
|
||||||
|
* measure round-trip-delays and packet loss across network paths.
|
||||||
|
*
|
||||||
|
* Author -
|
||||||
|
* Mike Muuss
|
||||||
|
* U. S. Army Ballistic Research Laboratory
|
||||||
|
* December, 1983
|
||||||
|
*
|
||||||
|
* Status -
|
||||||
|
* Public Domain. Distribution Unlimited.
|
||||||
|
* Bugs -
|
||||||
|
* More statistics could always be gathered.
|
||||||
|
* This program has to run SUID to ROOT to access the ICMP socket.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/uio.h>
|
||||||
|
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/ip.h>
|
||||||
|
#include <netinet/ip_icmp.h>
|
||||||
|
#include <netinet/ip_var.h>
|
||||||
|
#include <netinet/ip6.h>
|
||||||
|
#include <netinet/icmp6.h>
|
||||||
|
#include <netinet/ip_ah.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <err.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <poll.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <siphash.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define F_FLOOD 0x0001
|
||||||
|
#define F_INTERVAL 0x0002
|
||||||
|
#define F_HOSTNAME 0x0004
|
||||||
|
#define F_PINGFILLED 0x0008
|
||||||
|
#define F_QUIET 0x0010
|
||||||
|
#define F_RROUTE 0x0020
|
||||||
|
#define F_SO_DEBUG 0x0040
|
||||||
|
#define F_SHOWCHAR 0x0080
|
||||||
|
#define F_VERBOSE 0x0100
|
||||||
|
/* 0x0200 */
|
||||||
|
#define F_HDRINCL 0x0400
|
||||||
|
#define F_TTL 0x0800
|
||||||
|
#define F_TOS 0x1000
|
||||||
|
#define F_AUD_RECV 0x2000
|
||||||
|
#define F_AUD_MISS 0x4000
|
||||||
|
|
||||||
|
|
||||||
|
#define ECHOLEN 8 /* icmp echo header len excluding time */
|
||||||
|
#define ECHOTMLEN sizeof(struct payload)
|
||||||
|
#define DEFDATALEN (64 - ECHOLEN) /* default data length */
|
||||||
|
#define MAXIPLEN 60
|
||||||
|
#define MAXICMPLEN 76
|
||||||
|
#define MAXPAYLOAD (IP_MAXPACKET - MAXIPLEN - ECHOLEN)
|
||||||
|
#define IP6LEN 40
|
||||||
|
#define EXTRA 256 /* for AH and various other headers. weird. */
|
||||||
|
#define MAXPAYLOAD6 IPV6_MAXPACKET - IP6LEN - ECHOLEN
|
||||||
|
#define MAXWAIT_DEFAULT 10 /* secs to wait for response */
|
||||||
|
#define NROUTES 9 /* number of record route slots */
|
||||||
|
|
||||||
|
struct tv64 {
|
||||||
|
u_int64_t tv64_sec;
|
||||||
|
u_int64_t tv64_nsec;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct payload {
|
||||||
|
struct tv64 tv64;
|
||||||
|
u_int8_t mac[SIPHASH_DIGEST_LENGTH];
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *pr_addr(struct sockaddr *, socklen_t);
|
||||||
|
void pr_pack(u_char *, int, struct msghdr *);
|
||||||
|
/* IPv4 specific functions */
|
||||||
|
void pr_ipopt(int, u_char *);
|
||||||
|
int in_cksum(u_short *, int);
|
||||||
|
void pr_icmph(struct icmp *);
|
||||||
|
void pr_retip(struct ip *);
|
||||||
|
void pr_iph(struct ip *);
|
||||||
|
int map_tos(char *, int *);
|
||||||
|
|
||||||
|
int v6flag = 0;
|
||||||
|
int options = F_VERBOSE;
|
||||||
|
|
||||||
|
char BSPACE = '\b'; /* characters written for flood */
|
||||||
|
char DOT = '.';
|
||||||
|
int datalen = DEFDATALEN;
|
||||||
|
|
||||||
|
int64_t npackets; /* max packets to transmit */
|
||||||
|
int64_t nreceived; /* # of packets we got back */
|
||||||
|
int64_t nrepeats; /* number of duplicates */
|
||||||
|
int64_t ntransmitted; /* sequence # for outbound packets = #sent */
|
||||||
|
int64_t nmissedmax = 1; /* max value of ntransmitted - nreceived - 1 */
|
||||||
|
struct timeval interval = {1, 0}; /* interval between packets */
|
||||||
|
|
||||||
|
/* timing */
|
||||||
|
int timing; /* flag to do timing */
|
||||||
|
int timinginfo;
|
||||||
|
unsigned int maxwait = MAXWAIT_DEFAULT; /* max seconds to wait for response */
|
||||||
|
double tmin = 999999999.0; /* minimum round trip time */
|
||||||
|
double tmax; /* maximum round trip time */
|
||||||
|
double tsum; /* sum of all times, for doing average */
|
||||||
|
double tsumsq; /* sum of all times squared, for std. dev. */
|
||||||
|
|
||||||
|
struct tv64 tv64_offset;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* MAX_DUP_CHK is the number of bits in received table, i.e. the maximum
|
||||||
|
* number of received sequence numbers we can keep track of. Change 128
|
||||||
|
* to 8192 for complete accuracy...
|
||||||
|
*/
|
||||||
|
#define MAX_DUP_CHK (8 * 8192)
|
||||||
|
int mx_dup_ck = MAX_DUP_CHK;
|
||||||
|
char rcvd_tbl[MAX_DUP_CHK / 8];
|
||||||
|
|
||||||
|
#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
|
||||||
|
#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
|
||||||
|
#define SET(bit) (A(bit) |= B(bit))
|
||||||
|
#define CLR(bit) (A(bit) &= (~B(bit)))
|
||||||
|
#define TST(bit) (A(bit) & B(bit))
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
FILE *f;
|
||||||
|
size_t fsize;
|
||||||
|
uint8_t *buf;
|
||||||
|
|
||||||
|
f = fopen(argv[1], "rb");
|
||||||
|
fseek(f, 0, SEEK_END);
|
||||||
|
fsize = ftell(f);
|
||||||
|
rewind(f);
|
||||||
|
|
||||||
|
buf = malloc(fsize + 1);
|
||||||
|
if (buf == NULL)
|
||||||
|
err(1, NULL);
|
||||||
|
fread(buf, fsize, 1, f);
|
||||||
|
fclose(f);
|
||||||
|
|
||||||
|
pr_pack(buf, fsize, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pr_pack(u_char *buf, int cc, struct msghdr *mhdr)
|
||||||
|
{
|
||||||
|
struct ip *ip = NULL;
|
||||||
|
struct icmp *icp = NULL;
|
||||||
|
struct icmp6_hdr *icp6 = NULL;
|
||||||
|
struct timespec ts, tp;
|
||||||
|
struct payload payload;
|
||||||
|
struct sockaddr *from;
|
||||||
|
socklen_t fromlen;
|
||||||
|
double triptime = 0;
|
||||||
|
int i, dupflag;
|
||||||
|
int hlen = -1, hoplim = -1, echo_reply = 0;
|
||||||
|
u_int16_t seq;
|
||||||
|
u_char *cp, *dp;
|
||||||
|
char* pkttime;
|
||||||
|
|
||||||
|
if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1)
|
||||||
|
err(1, "clock_gettime(CLOCK_MONOTONIC)");
|
||||||
|
|
||||||
|
if (v6flag) {
|
||||||
|
#if 0
|
||||||
|
if (!mhdr || !mhdr->msg_name ||
|
||||||
|
mhdr->msg_namelen != sizeof(struct sockaddr_in6) ||
|
||||||
|
((struct sockaddr *)mhdr->msg_name)->sa_family !=
|
||||||
|
AF_INET6) {
|
||||||
|
if (options & F_VERBOSE)
|
||||||
|
warnx("invalid peername");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
from = (struct sockaddr *)mhdr->msg_name;
|
||||||
|
fromlen = mhdr->msg_namelen;
|
||||||
|
|
||||||
|
if (cc < sizeof(struct icmp6_hdr)) {
|
||||||
|
if (options & F_VERBOSE)
|
||||||
|
warnx("packet too short (%d bytes) from %s", cc,
|
||||||
|
pr_addr(from, fromlen));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
icp6 = (struct icmp6_hdr *)buf;
|
||||||
|
|
||||||
|
if ((hoplim = get_hoplim(mhdr)) == -1) {
|
||||||
|
warnx("failed to get receiving hop limit");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (icp6->icmp6_type == ICMP6_ECHO_REPLY) {
|
||||||
|
if (icp6->icmp6_id != ident)
|
||||||
|
return; /* 'Twas not our ECHO */
|
||||||
|
seq = icp6->icmp6_seq;
|
||||||
|
echo_reply = 1;
|
||||||
|
pkttime = (char *)(icp6 + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#if 0
|
||||||
|
if (!mhdr || !mhdr->msg_name ||
|
||||||
|
mhdr->msg_namelen != sizeof(struct sockaddr_in) ||
|
||||||
|
((struct sockaddr *)mhdr->msg_name)->sa_family != AF_INET) {
|
||||||
|
if (options & F_VERBOSE)
|
||||||
|
warnx("invalid peername");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
from = (struct sockaddr *)mhdr->msg_name;
|
||||||
|
fromlen = mhdr->msg_namelen;
|
||||||
|
#endif
|
||||||
|
/* Check the IP header */
|
||||||
|
ip = (struct ip *)buf;
|
||||||
|
hlen = ip->ip_hl << 2;
|
||||||
|
if (cc < hlen + ICMP_MINLEN) {
|
||||||
|
if (options & F_VERBOSE)
|
||||||
|
warnx("packet too short (%d bytes) from %s", cc,
|
||||||
|
pr_addr(from, fromlen));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now the ICMP part */
|
||||||
|
cc -= hlen;
|
||||||
|
icp = (struct icmp *)(buf + hlen);
|
||||||
|
if (icp->icmp_type == ICMP_ECHOREPLY) {
|
||||||
|
#if 0
|
||||||
|
if (icp->icmp_id != ident)
|
||||||
|
return; /* 'Twas not our ECHO */
|
||||||
|
#endif
|
||||||
|
seq = icp->icmp_seq;
|
||||||
|
echo_reply = 1;
|
||||||
|
pkttime = (char *)icp->icmp_data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (echo_reply) {
|
||||||
|
++nreceived;
|
||||||
|
if (cc >= ECHOLEN + ECHOTMLEN) {
|
||||||
|
SIPHASH_CTX ctx;
|
||||||
|
struct tv64 *tv64;
|
||||||
|
u_int8_t mac[SIPHASH_DIGEST_LENGTH];
|
||||||
|
|
||||||
|
memcpy(&payload, pkttime, sizeof(payload));
|
||||||
|
tv64 = &payload.tv64;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
SipHash24_Init(&ctx, &mac_key);
|
||||||
|
SipHash24_Update(&ctx, tv64, sizeof(*tv64));
|
||||||
|
SipHash24_Update(&ctx, &ident, sizeof(ident));
|
||||||
|
SipHash24_Update(&ctx, &seq, sizeof(seq));
|
||||||
|
SipHash24_Final(mac, &ctx);
|
||||||
|
|
||||||
|
if (timingsafe_memcmp(mac, &payload.mac,
|
||||||
|
sizeof(mac)) != 0) {
|
||||||
|
printf("signature mismatch from %s: "
|
||||||
|
"icmp_seq=%u\n", pr_addr(from, fromlen),
|
||||||
|
ntohs(seq));
|
||||||
|
--nreceived;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
timinginfo=1;
|
||||||
|
|
||||||
|
tp.tv_sec = betoh64(tv64->tv64_sec) -
|
||||||
|
tv64_offset.tv64_sec;
|
||||||
|
tp.tv_nsec = betoh64(tv64->tv64_nsec) -
|
||||||
|
tv64_offset.tv64_nsec;
|
||||||
|
|
||||||
|
timespecsub(&ts, &tp, &ts);
|
||||||
|
triptime = ((double)ts.tv_sec) * 1000.0 +
|
||||||
|
((double)ts.tv_nsec) / 1000000.0;
|
||||||
|
tsum += triptime;
|
||||||
|
tsumsq += triptime * triptime;
|
||||||
|
if (triptime < tmin)
|
||||||
|
tmin = triptime;
|
||||||
|
if (triptime > tmax)
|
||||||
|
tmax = triptime;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TST(ntohs(seq) % mx_dup_ck)) {
|
||||||
|
++nrepeats;
|
||||||
|
--nreceived;
|
||||||
|
dupflag = 1;
|
||||||
|
} else {
|
||||||
|
SET(ntohs(seq) % mx_dup_ck);
|
||||||
|
dupflag = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options & F_QUIET)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (options & F_FLOOD)
|
||||||
|
write(STDOUT_FILENO, &BSPACE, 1);
|
||||||
|
|
||||||
|
else if (options & F_SHOWCHAR) {
|
||||||
|
if (dupflag)
|
||||||
|
putchar('D');
|
||||||
|
else if (cc - ECHOLEN < datalen)
|
||||||
|
putchar('T');
|
||||||
|
else
|
||||||
|
putchar('!');
|
||||||
|
} else {
|
||||||
|
printf("%d bytes from %s: icmp_seq=%u", cc,
|
||||||
|
pr_addr(from, fromlen), ntohs(seq));
|
||||||
|
if (v6flag)
|
||||||
|
printf(" hlim=%d", hoplim);
|
||||||
|
else
|
||||||
|
printf(" ttl=%d", ip->ip_ttl);
|
||||||
|
if (cc >= ECHOLEN + ECHOTMLEN)
|
||||||
|
printf(" time=%.3f ms", triptime);
|
||||||
|
if (dupflag)
|
||||||
|
printf(" (DUP!)");
|
||||||
|
/* check the data */
|
||||||
|
if (cc - ECHOLEN < datalen)
|
||||||
|
printf(" (TRUNC!)");
|
||||||
|
if (v6flag)
|
||||||
|
cp = buf + ECHOLEN + ECHOTMLEN;
|
||||||
|
else
|
||||||
|
cp = (u_char *)&icp->icmp_data[ECHOTMLEN];
|
||||||
|
#if 0
|
||||||
|
dp = &outpack[ECHOLEN + ECHOTMLEN];
|
||||||
|
for (i = ECHOLEN + ECHOTMLEN;
|
||||||
|
i < cc && i < datalen;
|
||||||
|
++i, ++cp, ++dp) {
|
||||||
|
if (*cp != *dp) {
|
||||||
|
printf("\nwrong data byte #%d "
|
||||||
|
"should be 0x%x but was 0x%x",
|
||||||
|
i - ECHOLEN, *dp, *cp);
|
||||||
|
if (v6flag)
|
||||||
|
cp = buf + ECHOLEN;
|
||||||
|
else
|
||||||
|
cp = (u_char *)
|
||||||
|
&icp->icmp_data[0];
|
||||||
|
for (i = ECHOLEN; i < cc && i < datalen;
|
||||||
|
++i, ++cp) {
|
||||||
|
if ((i % 32) == 8)
|
||||||
|
printf("\n\t");
|
||||||
|
printf("%x ", *cp);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* We've got something other than an ECHOREPLY */
|
||||||
|
if (!(options & F_VERBOSE))
|
||||||
|
return;
|
||||||
|
printf("%d bytes from %s: ", cc, pr_addr(from, fromlen));
|
||||||
|
#if 0
|
||||||
|
if (v6flag)
|
||||||
|
pr_icmph6(icp6, buf + cc);
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
pr_icmph(icp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Display any IP options */
|
||||||
|
if (!v6flag && hlen > sizeof(struct ip))
|
||||||
|
pr_ipopt(hlen, buf);
|
||||||
|
|
||||||
|
if (!(options & F_FLOOD)) {
|
||||||
|
if (!(options & F_SHOWCHAR)) {
|
||||||
|
putchar('\n');
|
||||||
|
#if 0
|
||||||
|
if (v6flag && (options & F_VERBOSE))
|
||||||
|
pr_exthdrs(mhdr);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
fflush(stdout);
|
||||||
|
if (options & F_AUD_RECV)
|
||||||
|
fputc('\a', stderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pr_ipopt(int hlen, u_char *buf)
|
||||||
|
{
|
||||||
|
static int old_rrlen;
|
||||||
|
static char old_rr[MAX_IPOPTLEN];
|
||||||
|
struct sockaddr_in s_in;
|
||||||
|
in_addr_t l;
|
||||||
|
u_int i, j;
|
||||||
|
u_char *cp;
|
||||||
|
|
||||||
|
cp = buf + sizeof(struct ip);
|
||||||
|
|
||||||
|
s_in.sin_len = sizeof(s_in);
|
||||||
|
s_in.sin_family = AF_INET;
|
||||||
|
|
||||||
|
for (; hlen > (int)sizeof(struct ip); --hlen, ++cp) {
|
||||||
|
switch (*cp) {
|
||||||
|
case IPOPT_EOL:
|
||||||
|
hlen = 0;
|
||||||
|
break;
|
||||||
|
case IPOPT_LSRR:
|
||||||
|
printf("\nLSRR: ");
|
||||||
|
hlen -= 2;
|
||||||
|
j = *++cp;
|
||||||
|
++cp;
|
||||||
|
i = 0;
|
||||||
|
if (j > IPOPT_MINOFF) {
|
||||||
|
for (;;) {
|
||||||
|
l = *++cp;
|
||||||
|
l = (l<<8) + *++cp;
|
||||||
|
l = (l<<8) + *++cp;
|
||||||
|
l = (l<<8) + *++cp;
|
||||||
|
if (l == 0)
|
||||||
|
printf("\t0.0.0.0");
|
||||||
|
else {
|
||||||
|
s_in.sin_addr.s_addr = ntohl(l);
|
||||||
|
printf("\t%s",
|
||||||
|
pr_addr((struct sockaddr*)
|
||||||
|
&s_in, sizeof(s_in)));
|
||||||
|
}
|
||||||
|
hlen -= 4;
|
||||||
|
j -= 4;
|
||||||
|
i += 4;
|
||||||
|
if (j <= IPOPT_MINOFF)
|
||||||
|
break;
|
||||||
|
if (i >= MAX_IPOPTLEN) {
|
||||||
|
printf("\t(truncated route)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IPOPT_RR:
|
||||||
|
j = *++cp; /* get length */
|
||||||
|
i = *++cp; /* and pointer */
|
||||||
|
hlen -= 2;
|
||||||
|
if (i > j)
|
||||||
|
i = j;
|
||||||
|
i -= IPOPT_MINOFF;
|
||||||
|
if (i <= 0)
|
||||||
|
continue;
|
||||||
|
if (i == old_rrlen &&
|
||||||
|
cp == buf + sizeof(struct ip) + 2 &&
|
||||||
|
!memcmp(cp, old_rr, i) &&
|
||||||
|
!(options & F_FLOOD)) {
|
||||||
|
printf("\t(same route)");
|
||||||
|
i = (i + 3) & ~0x3;
|
||||||
|
hlen -= i;
|
||||||
|
cp += i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i < MAX_IPOPTLEN) {
|
||||||
|
old_rrlen = i;
|
||||||
|
memcpy(old_rr, cp, i);
|
||||||
|
} else
|
||||||
|
old_rrlen = 0;
|
||||||
|
|
||||||
|
printf("\nRR: ");
|
||||||
|
j = 0;
|
||||||
|
for (;;) {
|
||||||
|
l = *++cp;
|
||||||
|
l = (l<<8) + *++cp;
|
||||||
|
l = (l<<8) + *++cp;
|
||||||
|
l = (l<<8) + *++cp;
|
||||||
|
if (l == 0)
|
||||||
|
printf("\t0.0.0.0");
|
||||||
|
else {
|
||||||
|
s_in.sin_addr.s_addr = ntohl(l);
|
||||||
|
printf("\t%s",
|
||||||
|
pr_addr((struct sockaddr*)&s_in,
|
||||||
|
sizeof(s_in)));
|
||||||
|
}
|
||||||
|
hlen -= 4;
|
||||||
|
i -= 4;
|
||||||
|
j += 4;
|
||||||
|
if (i <= 0)
|
||||||
|
break;
|
||||||
|
if (j >= MAX_IPOPTLEN) {
|
||||||
|
printf("\t(truncated route)");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case IPOPT_NOP:
|
||||||
|
printf("\nNOP");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("\nunknown option %x", *cp);
|
||||||
|
if (cp[IPOPT_OLEN] > 0 && (cp[IPOPT_OLEN] - 1) <= hlen) {
|
||||||
|
hlen = hlen - (cp[IPOPT_OLEN] - 1);
|
||||||
|
cp = cp + (cp[IPOPT_OLEN] - 1);
|
||||||
|
} else
|
||||||
|
hlen = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pr_addr --
|
||||||
|
* Return address in numeric form or a host name
|
||||||
|
*/
|
||||||
|
const char *
|
||||||
|
pr_addr(struct sockaddr *addr, socklen_t addrlen)
|
||||||
|
{
|
||||||
|
static char buf[NI_MAXHOST];
|
||||||
|
int flag = 0;
|
||||||
|
|
||||||
|
return "not implemented";
|
||||||
|
|
||||||
|
if (!(options & F_HOSTNAME))
|
||||||
|
flag |= NI_NUMERICHOST;
|
||||||
|
|
||||||
|
if (getnameinfo(addr, addrlen, buf, sizeof(buf), NULL, 0, flag) == 0)
|
||||||
|
return (buf);
|
||||||
|
else
|
||||||
|
return "?";
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pr_icmph --
|
||||||
|
* Print a descriptive string about an ICMP header.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pr_icmph(struct icmp *icp)
|
||||||
|
{
|
||||||
|
switch(icp->icmp_type) {
|
||||||
|
case ICMP_ECHOREPLY:
|
||||||
|
printf("Echo Reply\n");
|
||||||
|
/* XXX ID + Seq + Data */
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH:
|
||||||
|
switch(icp->icmp_code) {
|
||||||
|
case ICMP_UNREACH_NET:
|
||||||
|
printf("Destination Net Unreachable\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_HOST:
|
||||||
|
printf("Destination Host Unreachable\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_PROTOCOL:
|
||||||
|
printf("Destination Protocol Unreachable\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_PORT:
|
||||||
|
printf("Destination Port Unreachable\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_NEEDFRAG:
|
||||||
|
if (icp->icmp_nextmtu != 0)
|
||||||
|
printf("frag needed and DF set (MTU %d)\n",
|
||||||
|
ntohs(icp->icmp_nextmtu));
|
||||||
|
else
|
||||||
|
printf("frag needed and DF set\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_SRCFAIL:
|
||||||
|
printf("Source Route Failed\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_NET_UNKNOWN:
|
||||||
|
printf("Network Unknown\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_HOST_UNKNOWN:
|
||||||
|
printf("Host Unknown\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_ISOLATED:
|
||||||
|
printf("Source Isolated\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_NET_PROHIB:
|
||||||
|
printf("Dest. Net Administratively Prohibited\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_HOST_PROHIB:
|
||||||
|
printf("Dest. Host Administratively Prohibited\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_TOSNET:
|
||||||
|
printf("Destination Net Unreachable for TOS\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_TOSHOST:
|
||||||
|
printf("Destination Host Unreachable for TOS\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_FILTER_PROHIB:
|
||||||
|
printf("Route administratively prohibited\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_HOST_PRECEDENCE:
|
||||||
|
printf("Host Precedence Violation\n");
|
||||||
|
break;
|
||||||
|
case ICMP_UNREACH_PRECEDENCE_CUTOFF:
|
||||||
|
printf("Precedence Cutoff\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Dest Unreachable, Unknown Code: %d\n",
|
||||||
|
icp->icmp_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Print returned IP header information */
|
||||||
|
pr_retip((struct ip *)icp->icmp_data);
|
||||||
|
break;
|
||||||
|
case ICMP_SOURCEQUENCH:
|
||||||
|
printf("Source Quench\n");
|
||||||
|
pr_retip((struct ip *)icp->icmp_data);
|
||||||
|
break;
|
||||||
|
case ICMP_REDIRECT:
|
||||||
|
switch(icp->icmp_code) {
|
||||||
|
case ICMP_REDIRECT_NET:
|
||||||
|
printf("Redirect Network");
|
||||||
|
break;
|
||||||
|
case ICMP_REDIRECT_HOST:
|
||||||
|
printf("Redirect Host");
|
||||||
|
break;
|
||||||
|
case ICMP_REDIRECT_TOSNET:
|
||||||
|
printf("Redirect Type of Service and Network");
|
||||||
|
break;
|
||||||
|
case ICMP_REDIRECT_TOSHOST:
|
||||||
|
printf("Redirect Type of Service and Host");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Redirect, Unknown Code: %d", icp->icmp_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
printf("(New addr: %s)\n",
|
||||||
|
inet_ntoa(icp->icmp_gwaddr));
|
||||||
|
pr_retip((struct ip *)icp->icmp_data);
|
||||||
|
break;
|
||||||
|
case ICMP_ECHO:
|
||||||
|
printf("Echo Request\n");
|
||||||
|
/* XXX ID + Seq + Data */
|
||||||
|
break;
|
||||||
|
case ICMP_ROUTERADVERT:
|
||||||
|
/* RFC1256 */
|
||||||
|
printf("Router Discovery Advertisement\n");
|
||||||
|
printf("(%d entries, lifetime %d seconds)\n",
|
||||||
|
icp->icmp_num_addrs, ntohs(icp->icmp_lifetime));
|
||||||
|
break;
|
||||||
|
case ICMP_ROUTERSOLICIT:
|
||||||
|
/* RFC1256 */
|
||||||
|
printf("Router Discovery Solicitation\n");
|
||||||
|
break;
|
||||||
|
case ICMP_TIMXCEED:
|
||||||
|
switch(icp->icmp_code) {
|
||||||
|
case ICMP_TIMXCEED_INTRANS:
|
||||||
|
printf("Time to live exceeded\n");
|
||||||
|
break;
|
||||||
|
case ICMP_TIMXCEED_REASS:
|
||||||
|
printf("Frag reassembly time exceeded\n");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Time exceeded, Unknown Code: %d\n",
|
||||||
|
icp->icmp_code);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pr_retip((struct ip *)icp->icmp_data);
|
||||||
|
break;
|
||||||
|
case ICMP_PARAMPROB:
|
||||||
|
switch(icp->icmp_code) {
|
||||||
|
case ICMP_PARAMPROB_OPTABSENT:
|
||||||
|
printf("Parameter problem, required option "
|
||||||
|
"absent: pointer = 0x%02x\n",
|
||||||
|
ntohs(icp->icmp_hun.ih_pptr));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Parameter problem: pointer = 0x%02x\n",
|
||||||
|
ntohs(icp->icmp_hun.ih_pptr));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pr_retip((struct ip *)icp->icmp_data);
|
||||||
|
break;
|
||||||
|
case ICMP_TSTAMP:
|
||||||
|
printf("Timestamp\n");
|
||||||
|
/* XXX ID + Seq + 3 timestamps */
|
||||||
|
break;
|
||||||
|
case ICMP_TSTAMPREPLY:
|
||||||
|
printf("Timestamp Reply\n");
|
||||||
|
/* XXX ID + Seq + 3 timestamps */
|
||||||
|
break;
|
||||||
|
case ICMP_IREQ:
|
||||||
|
printf("Information Request\n");
|
||||||
|
/* XXX ID + Seq */
|
||||||
|
break;
|
||||||
|
case ICMP_IREQREPLY:
|
||||||
|
printf("Information Reply\n");
|
||||||
|
/* XXX ID + Seq */
|
||||||
|
break;
|
||||||
|
case ICMP_MASKREQ:
|
||||||
|
printf("Address Mask Request\n");
|
||||||
|
break;
|
||||||
|
case ICMP_MASKREPLY:
|
||||||
|
printf("Address Mask Reply (Mask 0x%08x)\n",
|
||||||
|
ntohl(icp->icmp_mask));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
printf("Unknown ICMP type: %d\n", icp->icmp_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pr_iph --
|
||||||
|
* Print an IP header with options.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pr_iph(struct ip *ip)
|
||||||
|
{
|
||||||
|
int hlen;
|
||||||
|
u_char *cp;
|
||||||
|
|
||||||
|
hlen = ip->ip_hl << 2;
|
||||||
|
cp = (u_char *)ip + 20; /* point to options */
|
||||||
|
|
||||||
|
printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst Data\n");
|
||||||
|
printf(" %1x %1x %02x %04x %04x",
|
||||||
|
ip->ip_v, ip->ip_hl, ip->ip_tos, ip->ip_len, ip->ip_id);
|
||||||
|
printf(" %1x %04x", ((ip->ip_off) & 0xe000) >> 13,
|
||||||
|
(ip->ip_off) & 0x1fff);
|
||||||
|
printf(" %02x %02x %04x", ip->ip_ttl, ip->ip_p, ip->ip_sum);
|
||||||
|
printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_src.s_addr));
|
||||||
|
printf(" %s ", inet_ntoa(*(struct in_addr *)&ip->ip_dst.s_addr));
|
||||||
|
/* dump and option bytes */
|
||||||
|
while (hlen-- > 20) {
|
||||||
|
printf("%02x", *cp++);
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pr_retip --
|
||||||
|
* Dump some info on a returned (via ICMP) IP packet.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
pr_retip(struct ip *ip)
|
||||||
|
{
|
||||||
|
int hlen;
|
||||||
|
u_char *cp;
|
||||||
|
|
||||||
|
pr_iph(ip);
|
||||||
|
hlen = ip->ip_hl << 2;
|
||||||
|
cp = (u_char *)ip + hlen;
|
||||||
|
|
||||||
|
if (ip->ip_p == 6)
|
||||||
|
printf("TCP: from port %u, to port %u (decimal)\n",
|
||||||
|
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
|
||||||
|
else if (ip->ip_p == 17)
|
||||||
|
printf("UDP: from port %u, to port %u (decimal)\n",
|
||||||
|
(*cp * 256 + *(cp + 1)), (*(cp + 2) * 256 + *(cp + 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef SMALL
|
||||||
|
int
|
||||||
|
map_tos(char *key, int *val)
|
||||||
|
{
|
||||||
|
/* DiffServ Codepoints and other TOS mappings */
|
||||||
|
const struct toskeywords {
|
||||||
|
const char *keyword;
|
||||||
|
int val;
|
||||||
|
} *t, toskeywords[] = {
|
||||||
|
{ "af11", IPTOS_DSCP_AF11 },
|
||||||
|
{ "af12", IPTOS_DSCP_AF12 },
|
||||||
|
{ "af13", IPTOS_DSCP_AF13 },
|
||||||
|
{ "af21", IPTOS_DSCP_AF21 },
|
||||||
|
{ "af22", IPTOS_DSCP_AF22 },
|
||||||
|
{ "af23", IPTOS_DSCP_AF23 },
|
||||||
|
{ "af31", IPTOS_DSCP_AF31 },
|
||||||
|
{ "af32", IPTOS_DSCP_AF32 },
|
||||||
|
{ "af33", IPTOS_DSCP_AF33 },
|
||||||
|
{ "af41", IPTOS_DSCP_AF41 },
|
||||||
|
{ "af42", IPTOS_DSCP_AF42 },
|
||||||
|
{ "af43", IPTOS_DSCP_AF43 },
|
||||||
|
{ "critical", IPTOS_PREC_CRITIC_ECP },
|
||||||
|
{ "cs0", IPTOS_DSCP_CS0 },
|
||||||
|
{ "cs1", IPTOS_DSCP_CS1 },
|
||||||
|
{ "cs2", IPTOS_DSCP_CS2 },
|
||||||
|
{ "cs3", IPTOS_DSCP_CS3 },
|
||||||
|
{ "cs4", IPTOS_DSCP_CS4 },
|
||||||
|
{ "cs5", IPTOS_DSCP_CS5 },
|
||||||
|
{ "cs6", IPTOS_DSCP_CS6 },
|
||||||
|
{ "cs7", IPTOS_DSCP_CS7 },
|
||||||
|
{ "ef", IPTOS_DSCP_EF },
|
||||||
|
{ "inetcontrol", IPTOS_PREC_INTERNETCONTROL },
|
||||||
|
{ "lowdelay", IPTOS_LOWDELAY },
|
||||||
|
{ "netcontrol", IPTOS_PREC_NETCONTROL },
|
||||||
|
{ "reliability", IPTOS_RELIABILITY },
|
||||||
|
{ "throughput", IPTOS_THROUGHPUT },
|
||||||
|
{ NULL, -1 },
|
||||||
|
};
|
||||||
|
|
||||||
|
for (t = toskeywords; t->keyword != NULL; t++) {
|
||||||
|
if (strcmp(key, t->keyword) == 0) {
|
||||||
|
*val = t->val;
|
||||||
|
return (1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
#endif /* SMALL */
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
pr_exthdrs(struct msghdr *mhdr)
|
||||||
|
{
|
||||||
|
struct cmsghdr *cm;
|
||||||
|
|
||||||
|
for (cm = (struct cmsghdr *)CMSG_FIRSTHDR(mhdr); cm;
|
||||||
|
cm = (struct cmsghdr *)CMSG_NXTHDR(mhdr, cm)) {
|
||||||
|
if (cm->cmsg_level != IPPROTO_IPV6)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
switch (cm->cmsg_type) {
|
||||||
|
case IPV6_HOPOPTS:
|
||||||
|
printf(" HbH Options: ");
|
||||||
|
pr_ip6opt(CMSG_DATA(cm));
|
||||||
|
break;
|
||||||
|
case IPV6_DSTOPTS:
|
||||||
|
case IPV6_RTHDRDSTOPTS:
|
||||||
|
printf(" Dst Options: ");
|
||||||
|
pr_ip6opt(CMSG_DATA(cm));
|
||||||
|
break;
|
||||||
|
case IPV6_RTHDR:
|
||||||
|
printf(" Routing: ");
|
||||||
|
pr_rthdr(CMSG_DATA(cm));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
2455
htmlize.css
Normal file
2455
htmlize.css
Normal file
File diff suppressed because it is too large
Load Diff
19
index.org
Normal file
19
index.org
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
* Ramblings
|
||||||
|
- [[file:fuzzing-ping.org][2022-12-01: Fuzzing ping(8)]]
|
||||||
|
- [[file:algorithm-roll.org][2022-06-08: DNSSEC algorithm roll-over]]
|
||||||
|
- [[file:nsd-unbound-update.org][2020-12-07: nsd(8) / unbound(8) update]]
|
||||||
|
- [[file:secrets-manager.org][2019-10-20: Secrets Manager]]
|
||||||
|
- [[file:ports-hints.org][2014-12-21: ports hints]]
|
||||||
|
* External Writings & Presentations
|
||||||
|
- [[http://undeadly.org/cgi?action=article&sid=20131025090233][2013-10-25, undeadly: b2k13 hackathon report: Florian Obser (florian@) on nginx.conf(5), slowcgi]]
|
||||||
|
- [[http://undeadly.org/cgi?action=article&sid=20140721125020][2014-07-21, undeadly: g2k14: Florian Obser in IPv6 land]]
|
||||||
|
- [[http://undeadly.org/cgi?action=article&sid=20150805151453][2015-08-05, undeadly: c2k15: florian@ on building the hackathon network, httpd and pflow]]
|
||||||
|
- [[http://undeadly.org/cgi?action=article&sid=20151113082512][2015-11-16, undeadly: u2k15: florian@ on IPv6 hackery]]
|
||||||
|
- [[http://undeadly.org/cgi?action=article&sid=20160911000052][2016-09-10, undeadly: g2k16 Hackathon Report: Florian Obser on httpd, networking, acme-client, and more]]
|
||||||
|
- [[https://undeadly.org/cgi?action=article;sid=20170609013548][2017-07-09, undeadly: d2k17 Hackathon Report: Florian Obser on slaacd(8)]]
|
||||||
|
- [[https://undeadly.org/cgi?action=article;sid=20171113235334][2017-11-13, undeadly: p2k17 Hackathon report: Florian Obser on network stack progress, kernel relinking and more]]
|
||||||
|
- [[http://www.openbsd.org/papers/florian_slaacd_bsdcan2018.pdf][2018-06-09, BSDCan: slaacd(8) - A privilege separated and sandboxed IPv6 Stateless Address AutoConfiguration Daemon]], [[https://www.youtube.com/watch?v=tBQXZYotKvI][video]]
|
||||||
|
- [[https://undeadly.org/cgi?action=article;sid=20190413023608][2019-04-12, undeadly: t2k19 Hackathon Report: unwinding in Taipei]]
|
||||||
|
- [[http://www.openbsd.org/papers/bsdcan2019_unwind.pdf][2019-05-17, BSDCan: unwind(8) a privilege-separated, validating DNS recursive nameserver for every laptop]], [[https://www.youtube.com/watch?v=88SoI49nO4o][video]]
|
||||||
|
- [[https://archive.fosdem.org/2020/schedule/event/dns_unwind/][2020-02-01, FOSDEM: unwind(8) a privilege-separated, validating DNS recursive nameserver for every laptop]]
|
||||||
|
- [[https://undeadly.org/cgi?action=article;sid=20200922090542][2020-09-21, undeadly: k2k20 hackathon report: Florian Obser on DNS]]
|
48
nsd-unbound-update.org
Normal file
48
nsd-unbound-update.org
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
#+TITLE: nsd(8) / unbound(8) update
|
||||||
|
#+DATE: 2020-12-07
|
||||||
|
|
||||||
|
How to update =nsd(8)= and =unbound(8)= in OpenBSD base from NLnetLabs
|
||||||
|
upstream.
|
||||||
|
|
||||||
|
* nsd(8)
|
||||||
|
git clone from the upstream repository on [[https://github.com/NLnetLabs/nsd][github]].
|
||||||
|
#+begin_src shell
|
||||||
|
git pull
|
||||||
|
git diff NSD_4_3_6_REL..NSD_4_3_7_REL . ':!.cirrus.yml' ':!tpkg/*' \
|
||||||
|
':!contrib/*' ':!compat/' ':!README.md' ':!.gitignore' \
|
||||||
|
':!.buildkite/*' ':!makedist.sh' > ~/nsd_4.3.7_upstream.diff
|
||||||
|
cd /usr/src/usr.sbin/nsd
|
||||||
|
patch -Ep0 < ~/nsd_4.3.7_upstream.diff
|
||||||
|
autoheader-2.69
|
||||||
|
autoconf-2.69
|
||||||
|
make -f Makefile.bsd-wrapper obj
|
||||||
|
make -f Makefile.bsd-wrapper clean
|
||||||
|
make -f Makefile.bsd-wrapper -j4
|
||||||
|
#+end_src
|
||||||
|
We also need to update the version numbers in the man pages. For that
|
||||||
|
we download the release tar ball and generate a diff:
|
||||||
|
#+begin_src shell
|
||||||
|
diff -ru . /home/florian/nsd-4.3.7/ | fgrep -v Only > sync.diff
|
||||||
|
#+end_src
|
||||||
|
The diff then needs to be partially applied, some changes are
|
||||||
|
intentional.
|
||||||
|
|
||||||
|
* unbound(8)
|
||||||
|
I haven't done an unbound update in some time, this is probably
|
||||||
|
outdated.
|
||||||
|
git clone from the upstream repository on [[https://github.com/NLnetLabs/unbound][github]].
|
||||||
|
#+begin_src shell
|
||||||
|
git pull
|
||||||
|
git diff release-1.15.0..release-1.16.0 . \
|
||||||
|
':!contrib/*' ':!compat/' ':!README.md' ':!.gitignore' \
|
||||||
|
':!pythonmod/' ':!testdata/' ':!util/configlexer.c' \
|
||||||
|
':!util/configparser.c' ':!util/configparser.h' \
|
||||||
|
':!.buildkite/*' ':!makedist.sh' > ~/unbound_1.16.0_upstream.diff
|
||||||
|
cd /usr/src/usr.sbin/unbound
|
||||||
|
patch -Ep0 < ~/unbound_1.16.0_upstream.diff
|
||||||
|
autoheader-2.69
|
||||||
|
autoconf-2.69
|
||||||
|
make -f Makefile.bsd-wrapper obj
|
||||||
|
make -f Makefile.bsd-wrapper clean
|
||||||
|
make -f Makefile.bsd-wrapper -j4
|
||||||
|
#+end_src
|
22
ports-hints.org
Normal file
22
ports-hints.org
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#+TITLE: ports hints
|
||||||
|
#+SUBTITLE: Stuff about port building I always forget.
|
||||||
|
#+DATE: 2014-12-21
|
||||||
|
|
||||||
|
See also [[https://man.openbsd.org/bsd.port.mk][bsd.port.mk(5)]].
|
||||||
|
|
||||||
|
* Environment variables
|
||||||
|
+ FETCH_PACKAGES :: Instruct the package target to download packages
|
||||||
|
missing, only building them if no suitable packages are
|
||||||
|
found. Defaults to *No*.
|
||||||
|
|
||||||
|
For example: src_shell[:exports code]{make FETCH_PACKAGES=-Dsnap package}
|
||||||
|
|
||||||
|
* Make targets
|
||||||
|
+ makesum :: Creates the checksum file.
|
||||||
|
+ checksum :: Checks the upstream distribution tar ball (or other
|
||||||
|
archives) against the checksum file.
|
||||||
|
+ extract :: Extracts the tar ball.
|
||||||
|
+ build, all :: Build the port.
|
||||||
|
+ fake :: Do a fake port installation.
|
||||||
|
+ plist :: Create / update the plist file.
|
||||||
|
+ package :: Do all the things to create a package.
|
48
publish.el
Executable file
48
publish.el
Executable file
@ -0,0 +1,48 @@
|
|||||||
|
#!/usr/local/bin/emacs --script
|
||||||
|
|
||||||
|
(require 'package)
|
||||||
|
|
||||||
|
(package-initialize)
|
||||||
|
|
||||||
|
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
|
||||||
|
("elpa" . "https://elpa.gnu.org/packages/")
|
||||||
|
("org" . "http://orgmode.org/elpa/")))
|
||||||
|
|
||||||
|
(unless package-archive-contents
|
||||||
|
(package-refresh-contents))
|
||||||
|
|
||||||
|
(unless (package-installed-p 'use-package)
|
||||||
|
(package-install 'use-package))
|
||||||
|
(require 'use-package)
|
||||||
|
(setq use-package-always-ensure t)
|
||||||
|
|
||||||
|
(use-package htmlize)
|
||||||
|
|
||||||
|
(require 'ox-publish)
|
||||||
|
(require 'ox-html)
|
||||||
|
(require 'htmlize)
|
||||||
|
(require 'org)
|
||||||
|
|
||||||
|
(setq org-html-htmlize-output-type 'css)
|
||||||
|
|
||||||
|
(setq org-html-validation-link nil)
|
||||||
|
(setq org-publish-project-alist
|
||||||
|
'(("tlakh"
|
||||||
|
:base-directory "/var/www/htdocs/"
|
||||||
|
:publishing-function org-html-publish-to-html
|
||||||
|
:publishing-directory "/var/www/htdocs/"
|
||||||
|
:section-numbers nil
|
||||||
|
:with-author nil
|
||||||
|
:with-email nil
|
||||||
|
:with-timestamps nil
|
||||||
|
:with-toc nil
|
||||||
|
:with-creator: nil
|
||||||
|
:html-head-include-default-style: nil
|
||||||
|
:html-head "<link rel=\"stylesheet\"
|
||||||
|
href=\"simple.min.css\"
|
||||||
|
type=\"text/css\"/>
|
||||||
|
<link rel=\"stylesheet\"
|
||||||
|
href=\"htmlize.css\"
|
||||||
|
type=\"text/css\"/>")))
|
||||||
|
|
||||||
|
(org-publish "tlakh")
|
51
secrets-manager.org
Normal file
51
secrets-manager.org
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#+TITLE: Secrets Manager
|
||||||
|
#+DATE: 2019-10-20
|
||||||
|
* Intro
|
||||||
|
It seems like everyone eventually writes their own password
|
||||||
|
manager. This is my take on it.
|
||||||
|
+ Simple.
|
||||||
|
+ Reasonable chance of it still working in 20 years.
|
||||||
|
+ No dependency on fancy language du jour.
|
||||||
|
Secrets are stored in files. One file per secret. The file name is
|
||||||
|
used to identify the secret. Secrets are encrypted / decrypted using
|
||||||
|
[[https://humungus.tedunangst.com/r/reop][=reop(1)=]]. =reop(1)= is available in packages on OpenBSD and in homebrew
|
||||||
|
on macOS.
|
||||||
|
* Scripts
|
||||||
|
** encrypt
|
||||||
|
#+begin_src shell
|
||||||
|
#!/bin/sh
|
||||||
|
j="$@"
|
||||||
|
reop -E -m - -x "$j"
|
||||||
|
#+end_src
|
||||||
|
** decrypt
|
||||||
|
#+begin_src shell
|
||||||
|
#!/bin/sh
|
||||||
|
echo $1
|
||||||
|
reop -D -m - -x "$1"
|
||||||
|
#+end_src
|
||||||
|
** 2fa
|
||||||
|
As a bonus here is a script for two factor authentication.
|
||||||
|
[[https://www.nongnu.org/oath-toolkit/man-oathtool.html][=oathtool(1)=]] is available in packages on OpenBSD and homebrew as
|
||||||
|
=oath-toolkit=. Whether this is safe depends on your threat model.
|
||||||
|
#+begin_src shell
|
||||||
|
#!/bin/sh
|
||||||
|
/usr/local/bin/oathtool --totp --base32 `reop -D -m - -x "$1"`
|
||||||
|
#+end_src
|
||||||
|
* Epilogue
|
||||||
|
Storing secrets in files, one file per secret, lets us organise our
|
||||||
|
secrets in a file system hierarchy. This is a thing most people are
|
||||||
|
already familiar with. The file system hierarchy can be backuped and
|
||||||
|
tracked in a version control system.
|
||||||
|
|
||||||
|
When tracking the secrets in a version control system it is beneficial
|
||||||
|
to store one secret per file. One can track when the secret got
|
||||||
|
created and changed. This enables us to revert back to an old version.
|
||||||
|
|
||||||
|
When secrets are stored in one big encrypted container changes are
|
||||||
|
opaque to the version control system. Some change happened, but you
|
||||||
|
can't find out what changed. This might be a good thing.
|
||||||
|
|
||||||
|
A crypto container only tells you: here are some secrets. A secret per
|
||||||
|
file leaks meta information. If you get access to my secret storage
|
||||||
|
you can tell that I'm [[https://bsd.network/@florian][@florian@bsd.network]]. But you will not be able
|
||||||
|
to log in.
|
1
simple.min.css
vendored
Normal file
1
simple.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user