Singpolyma

Technical Blog

Archive for the "Tech" Category

How to force the default route to always use a specific interface on Ubuntu

Posted on

This post was written by Dave Vandervies (@dj3vande).

I think Ubuntu inherits the things that need to be configured for this to work directly from Debian; if that’s correct this information will be useful without modification for Debian systems. It may also be possible to configure dhclient on other Linuxes (and other *nixes) according to these notes; I don’t know whether the guts of dhclient-script come from Debian or from dhclient. In any case, looking at what dhclient-script does will be a good start.

So, I have a machine that’s attached to two networks.

Both networks have DHCP servers. Both DHCP servers give out router configuration. But one of those default routes is useless, so I want to force the system to always use the other network segment’s router as its default route.

(My use case is a virtual machine; one VM network is NATted to the outside world, and one is isolated on the host machine. This VM gets run on different host machines, which assign different network addresses to their virtual segments, but which interface is on which type of segment is fixed by the VM configuration. So here, unlike many multi-interface machines, it’s necessary to tie the default route to a particular *interface* and not a router address.)

It turns out that this isn’t hard to do, but it took a lot of googling (and several rounds of “Find something interesting, search on new keywords”) to find a solution that actually did what I needed; all of the obvious searches turn up information about how to set the default route to a fixed router IP, which only works when you’re always on the same network.

Before I get into the theory of operation, here’s the solution, for
impatient people:

cat << 'EOF' > /etc/dhcp/dhclient-enter-hooks.d/restrict-default-route
## Only the DHCP server talking to eth0 is allowed to give us a default
## route.  Other interfaces only get local-segment configuration.
case ${interface} in
  eth0)
    ;;
  *)
    unset new_routers
    ;;
esac
EOF

So, here’s how this works, since that might be useful for other complicated DHCP configuration tricks you want to do.

When dhclient needs to make system configuration changes, it does it by invoking /sbin/dhclient-script. The first nontrivial thing dhclient-script does is run the entry hooks in /etc/dhcp/dhclient-enter-hooks.d to allow local configuration rules to adjust things as necessary.

These hooks are shell script fragments sourced by the main script, so you can use them to edit the variables that make dhclient-script do things if you like. This is precisely what we want to do. $new_routers is the default gateway the DHCP server gave us; we only want to actually use it for the DHCP server eth0 is talking to, so if we’re on any other interface we unset it, to prevent dhclient-script from taking any action based on it.

You can use the same trick to ignore DNS settings (new_domain_name and new_domain_name_servers) if you want to ignore one network’s DNS servers; I didn’t need that in my configuration because the two subnets’ nameservers behave identically. (But note that if you need something more complicated than simply ignoring one of them, you’ll probably need more than just an entry hook.)

Heterogenous Collections in Haskell

Posted on

One of the things statically typed languages like Haskell and C often don’t have great support for, is collections that contain elements that are not all of the same type. In a dynamically typed language one can store any element of any type in a collection, because the type is finally determined later when the value is used at runtime. With a statically typed language, the compiler wants to determine all the types at compile time, and so it often wants to force every element to be of the same time (homogeneous collections).

Normally when this problem arises, I find that I can rethink the problem in a way such that the solution does not require heterogeneous collections, but recently I’ve been working with one that, while I can solve it another way, the most natural solution seems to call for this.

The Haskell Wiki has a couple of suggestions for doing this. The easiest one, is just to use Data.Dynamic to do dynamic typing from inside Haskell. The problem with this is that it is both slower (the types of all values in the collection have to be checked at runtime) and less safe (if a bad value gets put in the data structure, it can cause the application to crash).

Another solution suggested there is exitstentially qualified datatypes. These solve the problem in a way that is safe (as long as you only need to perform operations from some typeclass on the data) and efficient, and is analogous to an upcast in a statically-typed Object-Oriented language. However, it can be a bit complex, and is a language extension.

A solution that will work in Haskell98 and give most of the benefits of exitstentially qualified datatypes (with less power) is to package up operations to be performed with the datatype, instead of the data itself. Any functions that you will want to call (such as those which are members of the typeclass you’re interested in) can be partially applied to the data, resulting in a function that is the exact same type as an equivalent function partially applied to some other instance of the same typeclass. You can thus put records full of these functions into a list or other collection, and it will work because they are all the same datatype. Then instead of calling (func x otherparams) you can just call (func otherparams) and get exactly the same result.

An example:

class SomeClass a where
	somefun :: a -> Int -> Bool

instance SomeClass Int where
	somefun = (>)

instance SomeClass [a] where
	somefun = (>) . length

data SomeFunAble = SomeFunAble {
		somefun_ :: (Int -> Bool)
	}

someFunAble :: (SomeClass a) => a -> SomeFunAble
someFunAble v = SomeFunAble (somefun v)

somelist = [someFunAble "hello", someFunAble (12::Int)]

otherlist = map (`somefun_` 12) somelist

On Language Extensions (in Haskell and Elsewhere)

Posted on

This was originally an email to the Haskell web-devel list and was also posted on Reddit.

Somebody claiming to be yi huang wrote:

Why prefer code generation over template Haskell? Isn’t them essentially the same thing, and template haskell is performed automatically.

Also, from Reddit (nicolast):

I never understood why someone would want to avoid using language extensions which have been in GHC for at least some time. The only reason I can think of is: compatibility with other compilers. But is anyone ever going to compile/run a yesod-routes based application using something other than GHC?!

First off, yes, Template Haskell is very similar to code generation. There are a few reasons I would like to avoid it.

It’s a language extension. I try to avoid those in general, in every stanardized language I code in (C89, R5RS, Haskell98) for several reasons.

As nicolast said, compatibility with other compilers is a big one. When I get a piece of code from someone who assumed that “what MSVC does” or “what Racket does” is the same as “anyone can run this”, it makes it quite difficult to use my favourite implementations of those languages. I don’t want to make assumptions about other people’s environments, or what will be useful in the future. Maybe someone writes a Haskell interpreter that makes use in some context I haven’t even imagined much nicer. Who knows.

Additionally, any other static analysis/code processing tools (like, say, hlint) *also* needs to support whatever syntax extensions you’re using (semantics extensions may or may not apply here, depending on the nature of the tool). Requiring that every tool author support all my favourite extensions limits my tool options, and makes life harder for tool authors (since they cannot just look in one place for the spec and write to that anymore if they need to look up compilers’ extensions as well).

Will anyone ever compile/run/analyze a yesod-routes based application using something other than GHC/hlint? (Actually, does hlint support TH? It might.) What specifically about yesod-routes makes this less likely? What drew me to Yesod.Routes.Dispatch was its relative purity in terms of extensions/dependencies, etc.

Additionally, I find Template Haskell specifically (and some other language extensions, like Overlapping Instances) can make code harder to read (for me) and possibly harder to reason about. A code generator makes a file that I can read for comprehension, edit if I want to, etc.

Ok, that’s a bit of a long answer to a short question, but it sort of sums up my motivation vis extensions in general and TH in particular.

BitBrawl: Cleanup and Multiplayer

Posted on

I’ve pushed some stuff up to the BitBrawl repo. It’s really starting to come together!

First off: the art/data is in the repo now. I’m using the grass from the base assets for the background for now. I’ve also built a custom character from some of the art by Johannes Sjölund, and put the credits in my COPYING file. This sprite sheet has more animations than just “walk”, which will be very useful when I start work on combat.

I have also done some simple obvious things: players can no longer walk off the edge of the screen. The control configuration start screen now gives useful names for the keys, instead of internal names. Art and data are searched for in system folders, with a fallback to the current directory, instead of hardcoded paths. On you can find the headphones you have been looking for.

< img src=”https://singpolyma.net/wordpress/wp-content/uploads/2012/07/bitbrawl2-300 alt=”BitBrawl with 2 players” >

I’ve also upgraded the drawing/physics code to actually draw and control all the N players who join the game! So, while all they can do for now is walk around, you can actually add as many players as you want! (There’s a small bug in that if you add more players that can be shown across the screen, the menu will draw some of them off-screen. I’m not sure yet how I want to handle that.)


BitBrawl, Opening Screen

Posted on

It’s not got a very shiny look yet, but I’ve got an opening screen for BitBrawl working now that lets the players join and configure their controls simultaneously. Only one player is actually rendered once the game is started by pushing one of the configured START buttons, but it is progress!

BitBrawl Opening Screen

After the game is started, the player can, as before, walk about the screen using the controls as they were configured for player 1.

The code is a bit hacky, but I’m quite excited by my progress so far!