| 1 | PRELOAD-HACKS |
| 2 | ~~~~~~~~~~~~~ |
| 3 | |
| 4 | What is it? |
| 5 | |
| 6 | The preload-hacks distribution contains a couple of LD_PRELOAD- |
| 7 | able libraries which I find very useful. Well, one useful one, |
| 8 | and one which is really handy in theory. |
| 9 | |
| 10 | uopen Traps when a process is trying to open(2) a Unix-domain |
| 11 | socket, and does the appropriate socket(2)/connect(2) |
| 12 | dance instead. I've no idea why it doesn't work like |
| 13 | this in the first place. |
| 14 | |
| 15 | noip Traps when a process is trying to make an Internet |
| 16 | socket, and makes a Unix-domain socket instead. |
| 17 | |
| 18 | The first one is the one which is useful in theory but I've not |
| 19 | really made much use of in practice. |
| 20 | |
| 21 | |
| 22 | uopen |
| 23 | |
| 24 | The main use-case is variable signatures. Many mail and news |
| 25 | clients nowadays have built-in sigmonsters, which choose a |
| 26 | .signature at random from a collection. Some don't, of course, |
| 27 | which is a shame. It would be nice if the sigmonster was |
| 28 | detachable, so you could just write a sigmonster and attach it |
| 29 | to your favourite newsreader. It would extra nice if |
| 30 | newsreaders (and mail clients) don't have to use some kind of |
| 31 | weirdo sigmonster interface just to do this stupid thing with |
| 32 | .signatures. |
| 33 | |
| 34 | All mail and news clients know how to read a .signature file. |
| 35 | It's why it's got that name. So the right answer seems to be to |
| 36 | make this file magically have different contents each time it's |
| 37 | read. Noticing when someone tries to read a regular file is |
| 38 | just awful so let's not think about that idea any more. We |
| 39 | could make .signature be a named pipe; but named pipe servers |
| 40 | are very difficult to get right when there are multiple |
| 41 | simultaneous clients. Sockets are, of course, the right answer |
| 42 | when client/server architectures come up. And we've got a |
| 43 | convenient way of stashing sockets in the filesystem: PF_UNIX |
| 44 | sockets. |
| 45 | |
| 46 | So, we write our sigmonster: |
| 47 | |
| 48 | $ fwd -d from unix:$HOME/.signature to exec.fortune |
| 49 | |
| 50 | And now we check to see whether it works. |
| 51 | |
| 52 | $ cat ~/.signature |
| 53 | cat: /home/mdw/.signature: No such device or address |
| 54 | |
| 55 | Hmm. That blows. Surely it's obvious how to read from a |
| 56 | socket. But, no, the kernel won't do the socket/connect thing |
| 57 | for us. |
| 58 | |
| 59 | Enter uopen. |
| 60 | |
| 61 | $ uopen cat ~/.signature |
| 62 | Noise proves nothing. Often a hen who has merely laid an egg |
| 63 | cackles as if she laid an asteroid. |
| 64 | -- Mark Twain |
| 65 | |
| 66 | Joy! |
| 67 | |
| 68 | This isn't perfect. The file is weird and not a proper file. |
| 69 | Emacs will refuse to visit it as a result. But it /will/ |
| 70 | happily insert the contents of the file into existing buffers. |
| 71 | Hopefully other editors are similar. `less' wants the -f option |
| 72 | before it will bother. But actually it works pretty well. |
| 73 | |
| 74 | The right place for the functionality of uopen is in the kernel. |
| 75 | It shouldn't be difficult. I even submitted a patch to the |
| 76 | Linux kernel list to do precisely that, once, back in the days |
| 77 | of 2.0.x. It was ignored, and I gave up; the patch bitrotted |
| 78 | hopelessly. My LD_PRELOAD hack still works. There's no |
| 79 | configuration. It just works. |
| 80 | |
| 81 | My .signature has been `-- [mdw]' for years now, and that's |
| 82 | unlikely to change. So I don't actually use uopen very much. |
| 83 | But it's cool to know that it exists. |
| 84 | |
| 85 | |
| 86 | noip |
| 87 | |
| 88 | The basic idea |
| 89 | |
| 90 | This I use every day. All the time. Here's the use case. |
| 91 | We'll see some more examples later. |
| 92 | |
| 93 | Some random program has a client/server split between the main |
| 94 | guts of the thing and its user interface, and the two |
| 95 | communicate over TCP sockets. There are lots of examples: SLIME |
| 96 | (the Superior Lisp Interaction Mode for Emacs) runs a Common |
| 97 | Lisp system as a separate process. The SAGE notebook runs a web |
| 98 | server and you're meant to use a Javascript-supporting web |
| 99 | browser to drive it. All sorts of stuff. Usually the |
| 100 | programmer knew just enough to remember to bind the server's |
| 101 | listening socket to 127.0.0.1, to stop everyone on the Internet |
| 102 | from connecting, but often the security consciousness stops |
| 103 | there. If you're very lucky, there's some sort of password |
| 104 | mechanism. |
| 105 | |
| 106 | The problem, of course, occurs on a multi-user system. Binding |
| 107 | to localhost doesn't stop any other user of the same machine |
| 108 | from connecting. In the cases of SLIME and SAGE, this is a big |
| 109 | problem: both provide a full programming environment |
| 110 | (respectively Common Lisp and Python) which would let an |
| 111 | attacker do anything he likes in your name. |
| 112 | |
| 113 | Passwords are wretched as a security mechanism. Besides, I |
| 114 | shouldn't need a damned password to talk to one of my own |
| 115 | processes from another one of my own processes! The operating |
| 116 | system should be able to ensure that processes owned by the same |
| 117 | user can communicate securely. There's a whole filesystem with |
| 118 | access control and everything. |
| 119 | |
| 120 | The right answer is to use Unix-domain sockets, which live in |
| 121 | the filesystem and have proper access control applied to them. |
| 122 | But programmers are lazy, and Unix-domain sockets don't exist on |
| 123 | Windows (well, unless you install Cygwin, but I can see why |
| 124 | that's an unpopular idea). |
| 125 | |
| 126 | The noip LD_PRELOAD hack intercepts the socket(2) system call. |
| 127 | If the process is asking for a PF_INET socket, then it hands out |
| 128 | a PF_UNIX socket instead. If the process tries to bind(2) its |
| 129 | socket to 127.0.0.1:12345, say, then noip binds it to |
| 130 | /tmp/noip-USER/127.0.0.1:12345 instead (having previously |
| 131 | created the directory /tmp/noip-USER and made sure that nobody |
| 132 | else can get to it). If the process tries to connect(2) |
| 133 | somewhere, noip fixes up the address. The noip hack intercepts |
| 134 | 14 different system calls in order to prevent its systematic |
| 135 | dishonesty from being discovered. |
| 136 | |
| 137 | Configuration |
| 138 | |
| 139 | Running a program under noip effectively only allows it to talk |
| 140 | to other programs running under noip. This is sort of the idea, |
| 141 | but it's rather restrictive in practice. I can happily run |
| 142 | |
| 143 | $ noip emacs |
| 144 | |
| 145 | and start up SLIME, and Emacs and SLIME will communicate |
| 146 | securely over a Unix-domain socket without either of them |
| 147 | noticing. But now Emacs can't talk to anything other than |
| 148 | SLIME, which makes w3m-el less useful than it used to be, and, |
| 149 | worse, my Common Lisp programs can't talk to anything external |
| 150 | either, which may make writing network-aware Lisp programs |
| 151 | annoying. |
| 152 | |
| 153 | It gets worse with SAGE. I can run |
| 154 | |
| 155 | $ noip sage -notebook |
| 156 | |
| 157 | and in another window |
| 158 | |
| 159 | $ noip iceweasel http://localhost:8000/ |
| 160 | |
| 161 | (or Firefox, on Ubuntu), and the two will communicate happily. |
| 162 | But now my Iceweasel is crippled and can't actually talk to the |
| 163 | rest of the Internet. The point of the exercise was to make my |
| 164 | SAGE process secure, not to make me run two copies of Iceweasel |
| 165 | and have to cope with the inevitable profile fork. |
| 166 | |
| 167 | So noip can be configured. It still defaults to safety: |
| 168 | whenever the process asks for a new Internet socket, noip hands |
| 169 | it a fake plastic Unix-domain socket instead. But when the |
| 170 | process tries to bind or connect its socket, noip will look the |
| 171 | address up in a list decide what to do. If the result comes |
| 172 | back `allow', then noip will do a three-card Monte, rustling up |
| 173 | a real PF_INET socket and replacing the plastic imitation; if |
| 174 | the result comes back `deny' then noip will continue with its |
| 175 | elaborate deception. |
| 176 | |
| 177 | The configuration file lives in $HOME/.noip. Mine says |
| 178 | something like this. |
| 179 | |
| 180 | ## standard configuration |
| 181 | |
| 182 | ## debug |
| 183 | realconnect +127.0.0.1:6010-6020, +[::1]:6010-6020 |
| 184 | realconnect +127.0.0.1:53, +[::1]:53 |
| 185 | realconnect +local:22 |
| 186 | realconnect -127.0.0.0/8, -[::1] |
| 187 | realconnect -local |
| 188 | |
| 189 | What this says is as follows. |
| 190 | |
| 191 | * Don't produce debugging output, but let me turn it on easily |
| 192 | if I feel the urge. |
| 193 | |
| 194 | * Allow conversations with SSH-forwarded X displays, which |
| 195 | listen on the loopback interface. Notice that the IPv6 |
| 196 | address must be enclosed in square brackets because colons |
| 197 | are having to do double-duty here. |
| 198 | |
| 199 | * Allow conversations with my local DNS server. (I run |
| 200 | `unbound' on all of my servers, to do DNSsec validation. |
| 201 | The noip hack is not particularly discriminating. It |
| 202 | replaces UDP sockets with Unix-domain datagram sockets, just |
| 203 | as it replaces TCP sockets with Unix-domain stream sockets.) |
| 204 | |
| 205 | * Allow conversations with my local SSH server. |
| 206 | |
| 207 | * Don't allow any other communication with anything else on |
| 208 | the loopback network 127.0.0.0/8. (I've still no idea why |
| 209 | each machine needs 16 million IPv4 addresses for talking to |
| 210 | itself. The `-' means `deny'.) |
| 211 | |
| 212 | * Don't allow any other communication with any of my other |
| 213 | local IP addresses. (noip will work out which IP addresses |
| 214 | are local from your network interface configuration.) |
| 215 | |
| 216 | * And finally, implicitly, allow anything else. |
| 217 | |
| 218 | The rules follow the squid convention: the default is to do |
| 219 | whatever the last rule didn't do, so if the last rule says |
| 220 | `deny' then the default is `allow', and vice versa. |
| 221 | |
| 222 | Armed with this configuration, I now routinely run both Emacs |
| 223 | and Iceweasel exclusively under the control of noip. And I've |
| 224 | done this for several years. |
| 225 | |
| 226 | SSH tricks |
| 227 | |
| 228 | SSH is made of win. Its X forwarding is lovely. Its port |
| 229 | forwarding divine. Almost. |
| 230 | |
| 231 | Here's a common scenario. I'm running on a multi-user server, |
| 232 | shared with several other people whom I don't necessarily trust. |
| 233 | I want to check some files out from my office's version-control |
| 234 | system. Traditional answer: |
| 235 | |
| 236 | $ ssh -L 12345:vcs.work.com:345 mdw@gateway.work.com |
| 237 | |
| 238 | Now I can run |
| 239 | |
| 240 | $ vcs -d localhost:12345 checkout ... |
| 241 | |
| 242 | and all works well. Of course, anyone else on the server can do |
| 243 | the same thing, so I've just leaked my company's secret sauce. |
| 244 | (I don't believe in secret sauce, but I ought to show willing.) |
| 245 | |
| 246 | How do I fix this? Easy! |
| 247 | |
| 248 | $ noip ssh -L 12345:vcs.work.com:345 mdw@gateway.work.com |
| 249 | |
| 250 | $ noip vcs -d localhost:12345 checkout ... |
| 251 | |
| 252 | And it all works. In this case, in particular, it's essential |
| 253 | that the /same/ SSH process binds a safe, plastic local end to |
| 254 | its forwarded VCS port, and is able to make a real, potentially |
| 255 | dangerous Internet connection to gateway.work.com. Of course, |
| 256 | since I run Emacs under noip anyway, all the version control |
| 257 | stuff that Emacs does magically find the SSH tunnel and work |
| 258 | without me having to care. |
| 259 | |
| 260 | Testing |
| 261 | |
| 262 | noip provides a handy way for testing network servers and so on |
| 263 | safely. For a start, you can run your test server apparently on |
| 264 | the same port as the real one. Because noip consults the |
| 265 | environment variable NOIP_SOCKETDIR to find out where to put its |
| 266 | sockets, you can run two at a time and they don't interfere. |
| 267 | And noip doesn't care what port numbers your program tries to |
| 268 | bind, so you don't need to jump through stupid hoops in order to |
| 269 | test programs which use `privileged' ports. |
| 270 | |
| 271 | Other applications |
| 272 | |
| 273 | There are certainly loads of handy things you can do with noip. |
| 274 | If you think of one, let me know! |
| 275 | |
| 276 | Mark Wooding |
| 277 | mdw@distorted.org.uk |
| 278 | |
| 279 | \f |
| 280 | Local variables: |
| 281 | mode: text |
| 282 | fill-column: 72 |
| 283 | End: |