Monday, November 9, 2009

A Couple Issues Jailbreaking iPhone OS 3.1.2

I ran in to three issues jailbreaking iPhone 3GS OS 3.1.2 with PwnageTool 3.1.4:

1) Error 1064 when iTunes tried to deploy a custom image
2) No cellular signal after jailbreak
3) Cydia immediately crashing when you try to open it


--------------------------1--------------------------

The 1064 error was solved simply by pwning the phone again. The hardest part was getting the phone out of DFU mode. A couple of the published "hold home and power for 8 seconds, then hold home and power for 8 seconds, then again, but keep holding the home button for 20 seconds" methods didn't work. iRecovery worked perfectly first try. After downloading and extracting it run:


./iRecovery -s
#after the prompt appears enter:

setenv auto-boot true
saveenv
/exit

Note: In Windows XP this needs to be run in compatibility mode and as administrator...

Then just run the PwnageTool again and tell it the phone hasn't been pwned. This only happened to one of the phones I was messing with, so it could have been a user error.


--------------------------2--------------------------

This is just because I told PwnageTool to activate the phone even though I had a legite cell plan... Disabling the activation feature made everything work fine again.


--------------------------3--------------------------

I traced this issue back to using expert mode of PwnageTool and telling it to install all of the outdated pre-downloaded packages that come with PwnageTool. The fix is to either just not preinstall any packages, or to update the packages before they are installed.

The reason that simply hitting the refresh button under Cydia Settings->Download Packages doesn't work is because it is using a different repository than Cydia ends up using on the iPhone. So you have to go to "Manage sources" and remove the existing "http://apt.saurik.com/dists/tangelo/main/binary-iphoneos-arm/Packages" repository (click it and hit delete), then add "http://apt.saurik.com/dists/tangelo-3.7/main/binary-iphoneos-arm/Packages". Now go back to "Download packages", select the 3.7 repository, sort by Status, highlight all of the packages that have a new version available (shift+click), and click add to queue and wait for them to download. Now you can add all the packages you want via "Select packages" and create an image that won't cause Cydia to immediately crash.


-----------------------------------------------------

Another tidbit: iTunes asked me if I wanted to update my carrier settings. I was a bit skeptical after having just jailbroken the phone, but all it does is update some APN information and such, not the baseband or firmware or anything. So it is fine to say yes to AFAIK.

Also, I did notice the lowered WiFi signal after installing blackra1n, but a network settings reset seemed to fix it.

Friday, August 21, 2009

Drawable Image View in Android

I recently needed an image view that scaled a bitmap to its size and could be drawn on using a touchscreen.

Its not very polished or extensible (the line size and color is hardcoded), but it works well for a prototype: Update: I went ahead and made the color and line width configurable:


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.view.MotionEvent;
import android.view.View;

public class DrawableImageView extends View {
private Bitmap mBitmap;
private Bitmap pic;
private Canvas mCanvas;
private final Paint mPaint;
private int a = 255;
private int r = 255;
private int g = 255;
private int b = 255;
private float width = 4;

public DrawableImageView(Context c, Bitmap img) {
super(c);
pic = img;
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setARGB(a,r,g,b);


Bitmap newBitmap = Bitmap.createBitmap(img.getWidth(), img.getHeight(), Bitmap.Config.RGB_565);
Canvas newCanvas = new Canvas();
newCanvas.setBitmap(newBitmap);
if (img != null) {
newCanvas.drawBitmap(img, 0, 0, null);
}
mBitmap = newBitmap;
mCanvas = newCanvas;

mCanvas.setBitmap(mBitmap);
}

public DrawableImageView(Context c, Bitmap img, int alpha, int red, int green, int blue) {
this(c, img);
setColor(alpha, red, green, blue);
}
public DrawableImageView(Context c, Bitmap img, int alpha, int red, int green, int blue, float w) {
this(c, img, alpha, red, green, blue);
width = w;
}

public Bitmap getBitmap() {return mBitmap;}
public void setWidth(float w) {width = w;}
public void setColor(int alpha, int red, int green, int blue) {
a = alpha;
r = red;
g = green;
b = blue;
mPaint.setARGB(a,r,g,b);
}
public void Undo() {
mCanvas.drawBitmap(pic, 0, 0, null);
invalidate();
}

float scaleX;
float scaleY;
float scale;
@Override protected void onSizeChanged(int w, int h, int oldw, int oldh) {
scaleX = (float) w/mBitmap.getWidth();
scaleY = (float) h/mBitmap.getHeight();
scale = scaleX > scaleY ? scaleY : scaleX;
}

@Override protected void onDraw(Canvas canvas) {
if (mBitmap != null) {
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
canvas.drawBitmap(mBitmap, matrix, null);
//canvas.drawBitmap(mBitmap, 0,0, null);
}
}

float lastX;
float lastY;
@Override public boolean onTouchEvent(MotionEvent event) {
mPaint.setStrokeWidth(width/scale);

float curX = event.getX()/scale;
float curY = event.getY()/scale;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:{
mCanvas.drawCircle(curX, curY,width/2/scale, mPaint);
break;
}
case MotionEvent.ACTION_MOVE:{
mCanvas.drawLine(lastX, lastY, curX, curY, mPaint);
mCanvas.drawCircle(curX, curY,width/2/scale, mPaint); //fix for weird jaggies occur between line start and line stop
break;
}
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:{
mCanvas.drawLine(lastX, lastY, curX, curY, mPaint);
mCanvas.drawCircle(curX, curY,width/2/scale, mPaint);
break;
}

}
lastX = curX;
lastY = curY;
invalidate(); //invalidate only modified rect...

return true;
}
}


TouchPaint was used extensively to figure out how to do this, along with the standard 2d drawing doc.

For me the most non-obvious part of the whole 2d drawing thing was how canvases work. I originally didn't quite understand how a given canvas was linked to what was actually drawn on the screen. In short you have your own canvas, in this case mCanvas, that operates on your own bitmap, mBitmap, then when the onDraw(Canvas) method is called, you copy your bitmap over to the canvas that method provides. The canvas provided by onDraw is backed by the bitmap rendered to the screen, which is how your modifications actually make it to the screen.

Wednesday, July 15, 2009

Simple Hacking on Cisco WCS for Seamless Anonymous Browsing

My university has a Cisco network, which has all sorts of nice management features such as a wireless control system (WCS), vlans, CleanAccess, and I'm sure many more goodies. The wireless network broadcasts two SSIDs: one is for people associated with the university, requires credentials, and puts you in the appropriate vlan, the other is for visitors and provides completely anonymous access. The visitor network requires you to click a button to accept some University policy before you gain access, and this annoying redirect is reset every 6 hours or so. This is particularly cumbersome because if I open Firefox before accepting the policy then it redirects every saved tab to the policy page, and then to the university homepage.

I use the visitor network for various reasons, one is that because of some ridiculous network policies from the student vlan I can't get to some ports (svn, rdp, etc) on the DMZ vlan where I have a couple servers, despite the fact that 99% of the internet can access those ports. I think this is being fixed, but until then I need to use the visitor network. Also, I believe anonymous access to the internet is critical, but I am going to refrain from philosophical/political rants on a technical blog.

Just to procrastinate real work I decided to attempt to automate the policy accept process, and thus save my Firefox tabs.

I started by taking look at the policy page html and javascript, but it was a bit obtruse, so I went ahead and installed Firebug and took a look at its "Net" tab. Unfortunately since the policy page uses 20 gazillion different redirects, it kept changing pages before I could see what it was sending. (If anyone knows a workaround for this please let me know; I tried enabling redirect warnings in the Firefox preferences, but it didn't help.)

So I changed my hosts file to point wirelessauth.university.edu to 127.0.0.1, and fired up netcat. Turns out the policy page was accessing wirelessauth over ssl, so netcat was kind of useless. This also meant packet sniffers would be useless... So I just installed apache w/ ssl. This worked like a charm and I was able to use Firebug to see that it was POSTing some stuff to https://wirelesssauth.university.edu/login.html:

POST /login.html HTTP/1.1
Host: wirelessauth.university.edu
User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/20090331
00 Ubuntu/9.04 (jaunty) Firefox/3.0.8
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 300
Connection: keep-alive
Referer: http://www.university.edu/it/network/visitor_wireless/?switch_url=https://wirelessauth.university.edu/login.html&ap_mac=00:0b:85:7f:26:40&wlan=Visitor&redirect=woot.com/
Cookie: __utma=64401068.180182089960766140.1247531434.1247531434.1247531434.1; __utmz=64401068.1247531434.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmc=64401068

buttonClicked=4&err_flag=0&err_msg=&info_flag=0&info_msg=&redirect_url=


Notably it is sending all sorts of crap: cookies, host, referrer, url encoded values, etc. I replicated everything except for the cookies and used wget to send a login request. This worked just fine:

wget --post-data="buttonClicked=4&err_flag=0&err_msg=&info_flag=0&info_msg=&redirect_url=" --user-agent="Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.0.8) Gecko/2009033100 Ubuntu/9.04 (jaunty) Firefox/3.0.8" --referer="http://www.university.edu/it/network/visitor_wireless/?switch_url=https://wirelessauth.university.edu/login.html&ap_mac=00:0b:85:7f:26:40&wlan=Visitor&redirect=woot.com/" http://wirelessauth.university.edu/login.html


Turns out all you really need is:

wget --post-data="buttonClicked=4" https://wirelessauth.university.edu/login.html

Which is easy enough to remember :)


I did leave out one little detail... that is how I was able to play with the policy/login page without having to wait 6 hours for it to timeout. This is obvious for network guys, just disassociate from the wifi network and change your MAC address:

sudo ifconfig wlan0 down
sudo ifconfig wlan0 hw ether ##:##:##:##:##:##
sudo ifconfig wlan0 up


While disconnecting and forgetting a network in NetworkManager is relatively easy:

gconftool-2 --recursive-unset /system/networking/connections/1

I haven't figured out an easy way to add a connection from the cli. It is pretty simple to associate to a wifi network with other command line tools, but I would like to go through gconf/NetworkManager. This code snippet just removes the first remembered connection, there is probably a relatively easy way to do it by name too.

Since I'm on an anonymous wireless network (and booting from a livecd for that matter) it would be nice to have a random MAC address too. Putting it all together:

#!/bin/bash

gconftool-2 --recursive-unset /system/networking/connections/1

sudo ifconfig wlan0 down

#randomize... Almost all legite MACs start with 00
eth=00
for i in `seq 1 5`; do
eth=$eth:`head -c1 /dev/random |hexdump -e '1 "%x"'`
done
sudo ifconfig wlan0 hw ether $eth
sudo ifconfig wlan0 up

#need code to join network... for now just click, then do the wget manually
#wget --post-data="buttonClicked=4" https://wirelessauth.university.edu/login.html


After concocting my random MAC address generator I realized somebody else probably already did it. Sure enough here is one of the first hits. I like my method better because it actually uses the appropriate random number generator, not /proc/interrupts. That example leaves off the first byte, which should be 0. Both because most legitimate MAC addresses start with 00, and the 7th and 8th bits signify multi/unicast and global/local uniqueness. Granted you could probably just do:

MAC=00:`head /dev/urandom|md5sum| sed -r 's/^(.{10}).*$/\1/; s/([0-9a-f]{2})/\1:/g; s/:$//;'`

or:

MAC=00:`head -c5 /dev/urandom|hexdump -e '"%x"'| sed -r 's/(..)/\1:/g; s/:$//;'`

I'm using urandom rather than random because random can block, especially without mouse or keyboard movements. I don't know how random md5sum is (probably more than enough for this application), but the second example doesn't use it. Apparently bash also has a $RANDOM variable, but it is in decimal, not hex.

Saturday, June 20, 2009

QualNet (Scalable Networks Technologies) Website and Issues

I had a number of issues with the QualNet website, which ended up resulting in this email dated June 3rd to license@scalable-networks.com and
evals@scalable-networks.com:

Dear Scalable Networks,

I recently signed up for a 30 day evaluation of QualNet. When I log in I get a welcome message that states the following:

"Thank you for evaluating QualNet. Your 30-day Evaluation License File has been generated and posted to your download page."

However, when I go to the download page and click the link to the license file (http://www.scalable-networks.com/distributions/download/license/evals/qualnet-4.5.1-eval-2009.07.03.lic) I am immediately redirected to the sitemap (http://www.scalable-networks.com/sitemap.php). Since I am on Linux/Firefox and was having other issues with your site (such as broken CSS suckerfish dropdown menus), I decided to try logging in on a Windows PC.

This attempt was even more broken/disturbing, [since] as soon as I logged in I received a non-html page that stated:

INSERT INTO ErrorLog (UID, address, SID, error, login, password) VALUES ('', '#.#.#.#', 'nodnhkck0rlkh0qc2442skijh5', 'Password is not correct', 'my@email.com', 'MyPassword'')

Subsequent attempts to log in on the Windows machine do not even take me to the login page, they simply show this SQL query. I initial[ly] thought my password was correct, however if you look closely there is an extra single quote at the end of it, which I must have hit while submitting the form with the enter key. I had to clear my cookies in order to be able to log in correctly. Unfortunately the license file link was still broken (as were the dropdown menus).

In summary:

1. Your CSS suckerfish dropdown menus have extra pixels [between] them and the popup which causes them to break in Linux and Windows Firefox.
2. You are likely not sanitizing your user input before inserting it in to your SQL database, which is a huge security hole.
3. You are storing your passwords in plain-text which is a very, very, bad practice. A simple SQL injection could potentially reveal every stored password.
4. You are sending passwords in plain-text over email which is not necessarily encrypted; this is also a very bad security practice.
5. And most importantly, I still cannot download my evaluation license file. Please let me know what I need to do to get this.


Thank You,

Clayton Shepard



P.S. http://xkcd.com/327/

(I apologize for the typos, noted in brackets. Clearly I removed my plaintext password, IP, and email.)


I guess I just find it ironic, and somewhat amusing, that a technology oriented company has such glaring flaws with their website and security. In their defense they very promptly replied with the license file. Also, the SQL table was just the "ErrorLog", which means they could still be using a hash for the actual passwords somewhere else; arguably this is still a security threat though, since mistyped passwords are likely very close to the original. For obvious reasons I did not try a SQL injection attack, so I can not verify whether or not that is actually a security hole (although my guess is that it is).


On entirely different note, I was unable to get QualNet 4.5 running on Ubuntu 9.04 AMD64 because of library issues. In short they require gcc 4.0 and glibc2.3 or earlier to compile/install. Getting glibc2.3 to run on 9.04 is a huge pain. When asked, their official tech support reply is to use Ubuntu 6.06 :(. Unfortunate.


This reminds of the MSDNAA (MSDN Academic Alliance) website which also sends plaintext passwords in emails. Sigh.

Wednesday, June 17, 2009

Showing scp's Progress Using zenity (pseudo terminal example)

I recently discovered zenity for making quick, straightforward, graphical interfaces for shell scripts. One such script I wrote uses scp for backups. Since scp prints its percentage progress to stdout I figured it would be pretty easy to simply use a regex to parse the output and pipe it to zenity. I guessed this venture would take about ten minutes (I am not very experienced with regex), since zenity --progress just expects a number printed to its stdin in order to update the progress bar. I couldn't have been more mistaken; after four hours of hacking and wtfs I gave up. Finally, after a discussion with my old operating systems professor and a little bit of coding I finally have a solution.

After piping scp's output to various c and perl programs I determined that the problem was probably a terminal mode problem. A standard (canonical) terminal sends input to the program as lines, thus if there are never any new lines (such as in scp's output) the program would never receive the data. After figuring out how to put c (and perl) in to raw mode, as well as playing with stty, I managed to get a couple programs working that could read input before a newline was sent. I tested these with stdin and pipes and they seemed to work fine, but they still wouldn't work with scp. After a bit of debugging I figured out that when the data was piped to my c program I couldn't put the terminal in to raw mode. Go figure, when you pipe data to a program it doesn't use a terminal... it uses a pipe (duh!). This is the point where I gave up, as I didn't really feel like digging through the scp source code, and I certainly didn't want to run a modified copy of scp (that would kind of defeat the whole purpose).

After discussing the problem with an old professor he hypothesized that scp was checking if it was being run on a terminal, and if it wasn't then it was disabling output. Sure enough, on line 396 of scp.c:

if (!isatty(STDOUT_FILENO))
showprogress = 0;


As a possible solution he mentioned pseudo terminals. Apparently back in the old days psuedo terminals were quite a pain since you had to find a free one manually before you could use it. Luckily linux provides a convenient function, forkpty(), that finds a free pseudo terminal, forks a new process, and attaches the new process to the terminal. Sweet. Now with some simple fileio it works fine:


#include <unistd.h>
#include <sys/types.h>
#include <stdio.h>

main(int argc, char **argv) {
int fd;
pid_t pid;
char c,c1,c2;

if (argc != 3) {
printf("usage: [[user@]host1:]file1 [[user@]host2:]file2\n\nThis is a program that wraps scp and prints out the numeric progress on separate lines.\n");
fflush(stdout);
_exit(1);
}

pid = forkpty (&fd, NULL, NULL, NULL);
if (pid == 0) {
execlp ("scp", "scp", argv[1], argv[2], (char *) NULL);
_exit (1);
} else if (pid == -1) {
return 1;
} else {
FILE *F;

F = fdopen (fd, "r");

//reading character by character isn't horribly efficient...
while((c = fgetc(F)) != -1) {
if (c == '%') {
if (c1 == ' ')
printf("%c\n", c2); //one digit progess
else if (c1 == '0' && c2 == '0')
printf("100\n"); //done
else
printf("%c%c\n", c1,c2); //two digit progress
}
fflush(stdout);
c1 = c2;
c2 = c;
}

fflush (F);
wait (0);
}
return 0;
}


Notably, I went ahead and parsed the scp output in c. It seemed to be a cleaner solution than piping this output to a perl script and then to zenity. I initially missed the fflush() in the while loop, which took me a while to figure out :/.

To compile it you need to use the -lutil switch. So first copy and paste this c program in to scpwrap.c. Then run "gcc -lutil scpwrap.c -oscpwrap". Before you can use it you have to get rid of scp's authentication prompt by setting up some authentication keys:


ssh-keygen -t rsa
cat .ssh/id_rsa.pub | ssh user@example.com 'cat >> .ssh/authorized_keys'


Now to use the wrapper you can do something like:


./scpwrap /home/ubuntu/somefile user@example.com:~ | zenity --progress


Of course you can add whatever zenity switches you want. You cannot, however, add any scp switches without modifying the c program... Sorry.

---------------------Notes and Sources---------------------------

Terminal raw mode "stty raw".

Perl expression to parse the scp output:
perl -015 -l -ne 'print /(\d+)%/'
Notice the "-015" that tells it to use carriage returns as the line delimiter. Pretty cool, it probably would have worked if scp wasn't checking if it was running on a terminal.

Perl code to put terminal in to raw mode:

#!/usr/bin/perl

use Term::ReadKey;

ReadMode 5; # Turn off controls keys
while (($key=getc) ) {
print "$key\n";
last if $key eq "q";
};
print "Get key $key\n";
ReadMode 0; # Reset tty mode before exiting


C code to put terminal in to raw mode.

Zenity Progress Example 1:

(for a in `seq 1 100` ;


do
echo $a;
sleep 0.03;


done) | zenity --auto-close --progress \


--text="Slow counting from 1 to 100" \
--title="Example Progress"


Zenity Progress Example 2:

#!/bin/sh
(
echo "10" ; sleep 1
echo "# Updating mail logs" ; sleep 1
echo "20" ; sleep 1
echo "# Resetting cron jobs" ; sleep 1
echo "50" ; sleep 1
echo "This line will just be ignored" ; sleep 1
echo "75" ; sleep 1
echo "# Rebooting system" ; sleep 1
echo "100" ; sleep 1
) |
zenity --progress \
--title="Update System Logs" \
--text="Scanning mail logs..." \
--percentage=0

if [ "$?" = -1 ] ; then
zenity --error \
--text="Update canceled."
fi


Update: I modified the scp source (openssh5.2p1) to include a '-n' switch to print out the progress meter on new lines, regardless of whether stdout is a tty. I proposed this new feature to the openssh-unix-dev listserv, but I doubt they will adopt it. The email thread and patch can be found in their archives.

Update 2: Hrm, the pseudo terminal hack doesn't work if you run it from a launcher (kind of the whole point).

Wednesday, April 29, 2009

Printing from DOS in VirtualBox

VirtualBox doesn't support LPT ports. DOS has limited ability to print to USB printers, and the program I am using definitely doesn't support it. Thus I need to find an automatic, or at least semi-automatic, user friendly way to print from DOS.

----------------------------------- The Mount Method -------------------------------------

My first approach was to print to a file in DOS, then simply mount the .vdi and read/print the file.

This has three drawbacks:

1. You need sudo to mount the .vdi.
2. You can't use it with snapshots or non fixed sized disks.
3. I don't like mounting a disk that is already in use.

The first problem can be solved by adding an entry in the fstab or using FUSE. The second and third problems can be solved by printing to a floppy image and then mounting that instead.

So the basic process is go to Devices and mount a floppy image, print to the floppy using filename "print", unmount the floppy, then run this script in Linux:


#!/bin/bash
#we need recode (sudo apt-get install recode)
#add the floppy image to fstab to avoid sudo.
#mount writable and erase the print file so DOS doesn't prompt to overwrite?

mkdir -p ~/dosprint/printtemp
sudo mount -o loop,ro ~/dosprint/flopppy.img ~/dosprint/printtemp/
cp ~/printtemp/print ~/dosprint/printing
recode IBM437/CR-LF ~/dosprint/printing
lpr ~/dosprint/printing
umount ~/dosprint/printtemp
rmdir ~/dosprint/printtemp
rm ~/dosprint/printing

Notice that I am calling recode to convert the old DOS formatting. Obviously you will have to change floppy.img to match the floppy image you printed to.

This isn't a terrible option, but it does make the user have to remember the exact filename to print to, or else the script won't work. The whole mount/unmount process is a bit tedious too.


----------------------------------- The Serial Port Method -------------------------------------

To fix this I started looking at VirtualBox's COM emulation. It can connect the VM's COM port to a socket on the filesystem (it calls it a pipe, but it is really a socket... I probably would have preferred a real pipe). Anyway, after fiddling with it a bit I came up with a, hopefully, better solution.

After enabling COM1 on the VM to output to a "pipe" start up the VM. Then run socat -u UNIX-CONNECT:$HOME/dosprint/printpipe GOPEN:$HOME/dosprint/printfile in a terminal. You may have to do a 'sudo apt-get install socat' if it isn't already installed. The DOS VM now can print to COM1. After printing in DOS simply run this script:


#!/bin/bash
printfile="$HOME/dosprint/printfile"

#check to make sure the file exists and is not empty.
if [ ! -f $printfile ] || [ "`stat -c %s $printfile`" -le "1" ]; then
zenity --error --text "The Print File is Empty or Does Not Exist\!"
echo "" > $printfile
exit 1
fi

lpr $printfile

#check to make sure it printed
if [ "$?" -ne "0" ]; then
zenity --error --text "Error Printing!"
echo "" > $printfile
exit 1
fi

echo "" > $printfile
zenity --info --text "Printing\!"


There are probably some better ways to use socat here, but this worked the best so far. I would prefer to use a pipe, but it didn't work as expected. Also notice I didn't have to use recode, which was nice; this however is dependent on the printer driver DOS is using. In one incarnation I had to use dos2unix; unix2dos; then recode to get it to print properly. (In Ubuntu dos2unix is in the package 'tofrodos'.)

The biggest drawback here is that socat has to be run every time the VM is started, and you can't even run it as a startup script because it returns immediately unless the VM is running. At least it gets rid of the mounting and naming issues.

Here is a simple script to start the VM and run socat automatically:


#!/bin/bash
VirtualBox --startvm DOS&
echo "" > ~/dosprint/printfile
sleep 5
socat -u UNIX-CONNECT:$HOME/dosprint/printpipe GOPEN:$HOME/dosprint/printfile


You can create a launcher (right click desktop or nautilus window) if you want to be able to open this script without being prompted to run in terminal or display.

P.S. Zenity is very nice :).

Thanks to Maciej BliziƄski for some nice info on VirtualBox's serial port pipes.

Update: I ended up using iconv rather than recode, since recode had some problems with some special characters. Careful with iconv, it changed between the version on Ubuntu 8.04 and 8.10 (mainly the overwrite in place functionality).

Monday, April 27, 2009

Mount Xen and VirtualBox Images in Linux

If you use Xen disk images then you can mount them fairly easily to directly modify them on dom0 or another system:

Use "fdisk -luC 530 WinXP.disk" to print the partition table of the disk (where WinXP.disk is your disk image...).
Then multiply sector size by the sector start of the partition you want, then simply mount using that offset:
"sudo mount -o loop,offset=32256 WinXP.disk /media/mountpoint"

For example:
fdisk -luC 530 WinXP.disk

Disk WinXP.disk: 0 MB, 0 bytes
255 heads, 63 sectors/track, 530 cylinders, total 0 sectors
Units = sectors of 1 * 512 = 512 bytes
Disk identifier: 0x6c896c89

Device Boot Start End Blocks Id System
WinXP.disk1 * 63 41913584 20956761 7 HPFS/NTFS
Partition 1 has different physical/logical endings:
phys=(1023, 254, 63) logical=(2608, 254, 63)


Then 63 sectors * 512 bytes per sector =32256, so:
sudo mount -o loop,offset=32256 WinXP.disk /media/mountpoint

This info was found here.


In VirtualBox the operation is similar, but since the .vdi format is different you have to jump through another hoop. Note this only works with fixed size images. First you have to find the start of the disk, then use that to find the start of the partition:

od -j344 -N4 -td4 image.vdi | awk 'NR==1{print $2;}'

Now use the number it returns as #offset# in:
dd if=image.vdi of=vdstart bs=1 skip=#offset# count=1b
/sbin/sfdisk -luS vdstart


This takes the partition table of the virtual disk, dumps it to a file, then reads the partition table to tell you where the partition starts. Now the process is similar to Xen, multiply the sector size by the sector offset of the partition to find the start of the partition, but you also have to add the vdi offset you found before. You can then use that offset to mount the partition:
mount -o loop,offset=39424,ro image.vdi /media/image/

For Example:

$ od -j344 -N4 -td4 DOS.vdi | awk 'NR==1{print $2;}'
7168
$ dd if=DOS.vdi of=vdstart bs=1 skip=7168 count=1b
512+0 records in
512+0 records out
512 bytes (512 B) copied, 0.00523881 s, 97.7 kB/s
$sfdisk -luS vdstart
Disk vdstart: cannot get geometry

Disk vdstart: 0 cylinders, 255 heads, 63 sectors/track
Warning: The partition table looks like it was made
for C/H/S=*/64/63 (instead of 0/255/63).
For this listing I'll assume that geometry.
Units = sectors of 512 bytes, counting from 0

Device Boot Start End #sectors Id System
vdstart1 * 63 3253823 3253761 6 FAT16
vdstart2 0 - 0 0 Empty
vdstart3 0 - 0 0 Empty
vdstart4 0 - 0 0 Empty
$sudo mount -o loop,offset=39424,ro DOS.vdi /media/dos/


The mount offset was calculated by: 7168 (vdi header) + 63 (sectors) * 512 (bytes per sector) = 39424


Works like a charm :) Thanks Przemoc. More info can be found here.

I am still looking for a way to do it with Snapshots though :/. On a different note, this looks like it could be useful.

Sunday, April 12, 2009

WPA Enterprise on Android HTC G1 Dream

Unfortunately Android still does not have a GUI interface for connecting to corporate/enterprise networks; however, it does support it. While this isn't a solution for most users, it is fairly easy for those who have already rooted their phone or aren't scared of the command line.

First, you need to root your phone or else you can't get to the files you need to configure. Newer firmwares aren't as easy to root as older ones; either way this tutorial should walk you through what you need to do. It is very user friendly, and if you have any problems then it is probably addressed later in the forum comments. I had two problems when I did it:

1) I skipped the reformatting of the SD card since mine was already FAT. For some reason the phone needs FAT32 in order to recognize boot files... So don't skip this step.

2) The first link, and corresponding MD5 sum, to the modified OS images are to the BuildEnvironments rather than the actual OS image. Just go to the second link and download the actual image (it will be a zip file and 40.5MB rather than a .tar.gz that is 7.5MB). Hopefully Koush will update the post and fix this.

Anyway, after your device is rooted pull up a command prompt on the phone somehow. If you already know how to do this then skip ahead. You have a couple options:

1) All on the phone: I am pretty sure the terminal emulator comes pre-installed on that image. If not then you can just download it from the Market. You can just use this, but I wouldn't recommend it unless you really like typing on your phone.

2) Through telnetd: Use the terminal emulator then type "su" then enter. This will pull up the super user whitelist prompt. Tell it "Yes" that is okay for the Terminal to run as super user. Meanwhile the terminal may timeout, in which case you need to type it again. You can that you are root by running "whoami" which will tell you that you are uid 0 if you are root. Make sure the phone is connected to wifi. You can get the IP from the Wireless gui or running "ip a". Now run "telnetd". From another computer on the network run "telnet #android_IP#" where #android_IP# is the IP of the phone.

3) Using the debugger: This involves doing this then looking at this. If your device is all set up and plugged in to a computer this entails basically running "adb shell".


Now all you have to do is edit the /data/misc/wifi/wpa_supplicant.conf file. You can do this by copying it to your sdcard, editing it on a computer, then copying it back. I prefer just to edit in place. Update: Sorry I forgot to mention you need to run "su" first, or else you will get permission denied errors.

Regardless, you probably first want to backup the existing wpa_supplicant.conf file:

cd /data/misc/wifi/
cp wpa_supplicant.conf wpa_supplicant.conf.orig


To copy to sdcard (make sure you have one in there):

cd /data/mis/wifi/
cp wpa_supplicant.conf /sdcard


To edit in place:

cd /data/mis/wifi/
vi wpa_supplicant.conf


The wpa_supplicant file will contain all of your remembered wifi networks. Something like:

ctrl_interface=tiwlan0
update_config=1

network={
ssid="linksys"
key_mgmt=NONE
priority=11
}


Now add the parameters for your network. Many schools/business will provide this config for you, so you can just copy it over. Mine looks like:

ctrl_interface=tiwlan0
update_config=1

eapol_version=1
fast_reauth=1
network={
ssid="Some SSID"
scan_ssid=1
key_mgmt=WPA-EAP
eap=TTLS
identity="USERID"
password="PASSWORD"
phase2="auth=PAP"
priority=1
}

network={
ssid="linksys"
key_mgmt=NONE
priority=11
}


This will now make "Some SSID" show up as remembered on the WiFi config GUI screen, and when in range, if everything is configured right, it will connect automatically. Note that in this case my password is stored in plain text on a file in my phone. This is bad, but I'm not sure there is a way around it at this point.

More information on how to configure this can be found here.

Notably Android automatically deleted the eapol_version=1 and fast_reauth=1 lines, however it still works fine.

There is a relate Google code issue here.

Update: I am having problems with the phone rapidly associating and disassociating from every AP in range. I filed a bug report here.

Update: This is fixed in Haykuro's latest build.

Update:
Allegedly there is a program in the market that can do all of this from a GUI (although you still need a rooted phone). It is called Wifi Helper by Fan Zhang; I haven't tested it personally yet. I kind of doubt it fixes the AP hopping issue on older versions.

Monday, February 9, 2009

WTF Nokia? N810 and E71 Won't Charge from USB?

This is completely retarded. It almost makes them unusable. Even worse, the frakin charger is is 5v... I'm half tempted to tear the devices open and put a trace wire from the usb connector to the charger connector so it will automatically charge. I like being able to use my laptop as a backup battery for my other devices. I like being able to use one cord to charge any device. I like being able to carry a small generic cord that I can plug in to the front of any computer rather than a large charger that I have to dig under the desk to plug in...

It doesn't matter how awesome your device is, but you can really piss people off if you do something stupid like this. On that note, why the hell doesn't the iPhone support A2DP (or HID, or USB Mass Storage, or SD...)?


Ugh.

Forms: FDF, PDF, and PHP

I have always been somewhat opposed to PDF documents. While they are great for cross-platform viewing and printing, the inability to edit them without buying special software was philosophically unacceptable. Also, not being able to save forms you fill out is really stupid. While there are some free alternatives now, they are really a kind of pain in the ass compared to Adobe Professional. So, unfortunately, that is what I used to get this to work quickly and easily. Thanks to Justin Koivisto, who's tutorial really helped.

For those of you that don't know (as I didn't before starting this project), FDF files are used to save filled out PDF forms, however they don't store the original PDF document. Instead the FDF file just has a pointer to the PDF document which can either be on the local computer or on the web.

So here is the scenario:

1) User fills out an online form.
2) PHP parses the form, and creates a VCard as well as an FDF.
3) PHP emails the files as attachments, and displays the filled out PDF for the user to print.

This is very useful for populating PDF forms that already exist, and may be in use in paper form. This makes it easy to transition to an electronic system.


The first step is a standard HTML form that will submit the data to a PHP script (application.html):

<html>
<body>
<form method="post" action="./submit.php">
<table>
<tr><td>First Name</td><td><input type="text" name="firstName" /></td></tr>
<tr><td>Last Name</td><td><input type="text" name="lastName" /></td></tr>
<tr><td>Mobile Phone Number</td><td><input type="text" name="mobilePhone" /></td></tr>
<tr><td>Home Phone Number</td><td><input type="text" name="homePhone" /></td></tr>
<tr><td>E-Mail</td><td><input type="text" name="email" /></td></tr>
<tr><td>Date of Birth (MM-DD-YYYY)</td><td><input type="text" name="dobMonth" maxlength="2" size="2"/>-<input type="text" name="dobDay" maxlength="2" size="2"/>-<input type="text" name="dobYear" maxlength="4" size="4"/></td></tr>
<tr><td>Address</td><td><input type="text" name="address" /></td></tr>
<tr><td>City</td><td><input type="text" name="city" /></td></tr>
<tr><td>State</td><td><input type="text" name="state" /></td></tr>
<tr><td>Zip Code</td><td><input type="text" name="zip" /></td></tr>
<!--<tr><td></td><td><input type="text" name="" /></td></tr>-->
<tr><td>Age</td><td><input type="text" name="age" /></td></tr>
</table>
<input type="submit" value="Submit" />
</form>
</body>
</html>



Next is the PHP script to create the VCard and FDF, emails them, and displays the FDF (submit.php):

<?php

include("./vcard.php");
include("./fdf.php");
include ("./mail_attachment.php");

$emailto = "someone@example.com";

//The pdf file that the fdf file points to:
$pdf_doc='http://example.com/application.pdf';


//We need to check POST variables to make sure the form was submitted correctly, we should also make sure they don't enter more than one email address, and that they enter an email address
/*
if(isset($_POST["firstName"])) {
echo $_POST["firstName"];
}
else
echo "BAD!!!!";
*/
$v = new vCard();

$v->setPhoneNumber($_POST["mobilePhone"], "PREF;CELL;VOICE");
$v->setPhoneNumber($_POST["homePhone"], "PREF;HOME;VOICE");
$v->setName($_POST["lastName"], $_POST["firstName"], "", "");
$v->setBirthday($_POST["dobYear"]."-".$_POST["dobMonth"]."-".$_POST["dobDat"]);
$v->setAddress("", "", $_POST["address"], $_POST["city"], $_POST["state"], $_POST["zip"], "US");
$v->setEmail($_POST["email"]);
//$v->setNote("You can take some notes here.\r\nMultiple lines are supported via \\r\\n.");
//$v->setURL("http://www.thomas-mustermann.de", "WORK");
/*
$output = $v->getVCard();
$filename = $v->getFileName();

Header("Content-Disposition: attachment; filename=$filename");
Header("Content-Length: ".strlen($output));
Header("Connection: close");
Header("Content-Type: text/x-vCard; name=$filename");

echo $output;*/

/*$outfdf = fdf_create();
fdf_set_value($outfdf, "volume", $volume, 0);

fdf_set_file($outfdf, "http:/testfdf/resultlabel.pdf");
fdf_save($outfdf, "outtest.fdf");
fdf_close($outfdf);
Header("Content-type: application/vnd.fdf");
$fp = fopen("outtest.fdf", "r");
fpassthru($fp);
unlink("outtest.fdf");*/

foreach($_POST as $name => $val) {
$data[$name] = $val;
//echo $name."<br/>";
}


// generate the file content
$fdf_data=createFDF($pdf_doc,$data);
$attachments[0]['data']=$v->getVCard();
$attachments[0]['filename']=$_POST['firstName'].$_POST['lastName'].".vcf";
$attachments[0]['mime']="text/x-vcard";

$attachments[1]['data']=$fdf_data;
$attachments[1]['filename']=$_POST['firstName'].$_POST['lastName'].".fdf";
$attachments[1]['mime']="application/vnd.fdf";

$from=$_POST['firstName']." ".$_POST['lastName']." <".$_POST['email'].">";

mail_attachment($from,$emailto,"Rental Application", "Lease: from ".$_POST['leaseStart']." to ".$_POST['leaseEnd'], $attachments);
Header("Content-type: application/vnd.fdf");
echo $fdf_data;

?>

This shows an example of how to use the multi-attachment email script shown below. We should be checking the POST inputs to make sure someone isn't trying to do something nasty, there could be a security problem there.


Notably, there included files that you need. The first is the VCard creator (vcard.php):

<?

/***************************************************************************



PHP vCard class v2.0

(c) Kai Blankenhorn

www.bitfolge.de/en

kaib@bitfolge.de





This program is free software; you can redistribute it and/or

modify it under the terms of the GNU General Public License

as published by the Free Software Foundation; either version 2

of the License, or (at your option) any later version.



This program is distributed in the hope that it will be useful,

but WITHOUT ANY WARRANTY; without even the implied warranty of

MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the

GNU General Public License for more details.



You should have received a copy of the GNU General Public License

along with this program; if not, write to the Free Software

Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.



***************************************************************************/





function encode($string) {

return escape(quoted_printable_encode($string));

}



function escape($string) {

return str_replace(";","\;",$string);

}



// taken from PHP documentation comments

function quoted_printable_encode($input, $line_max = 76) {

$hex = array('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');

$lines = preg_split("/(?:\r\n|\r|\n)/", $input);

$eol = "\r\n";

$linebreak = "=0D=0A";

$escape = "=";

$output = "";



for ($j=0;$j<count($lines);$j++) {

$line = $lines[$j];

$linlen = strlen($line);

$newline = "";

for($i = 0; $i < $linlen; $i++) {

$c = substr($line, $i, 1);

$dec = ord($c);

if ( ($dec == 32) && ($i == ($linlen - 1)) ) { // convert space at eol only

$c = "=20";

} elseif ( ($dec == 61) || ($dec < 32 ) || ($dec > 126) ) { // always encode "\t", which is *not* required

$h2 = floor($dec/16); $h1 = floor($dec%16);

$c = $escape.$hex["$h2"].$hex["$h1"];

}

if ( (strlen($newline) + strlen($c)) >= $line_max ) { // CRLF is not counted

$output .= $newline.$escape.$eol; // soft line break; " =\r\n" is okay

$newline = " ";

}

$newline .= $c;

} // end of for

$output .= $newline;

if ($j<count($lines)-1) $output .= $linebreak;

}

return trim($output);

}



class vCard {

var $properties;

var $filename;



function setPhoneNumber($number, $type="") {

// type may be PREF | WORK | HOME | VOICE | FAX | MSG | CELL | PAGER | BBS | CAR | MODEM | ISDN | VIDEO or any senseful combination, e.g. "PREF;WORK;VOICE"

$key = "TEL";

if ($type!="") $key .= ";".$type;

$key.= ";ENCODING=QUOTED-PRINTABLE";

$this->properties[$key] = quoted_printable_encode($number);

}



// UNTESTED !!!

function setPhoto($type, $photo) { // $type = "GIF" | "JPEG"

$this->properties["PHOTO;TYPE=$type;ENCODING=BASE64"] = base64_encode($photo);

}



function setFormattedName($name) {

$this->properties["FN"] = quoted_printable_encode($name);

}



function setName($family="", $first="", $additional="", $prefix="", $suffix="") {

$this->properties["N"] = "$family;$first;$additional;$prefix;$suffix";

$this->filename = "$first%20$family.vcf";

if ($this->properties["FN"]=="") $this->setFormattedName(trim("$prefix $first $additional $family $suffix"));

}



function setBirthday($date) { // $date format is YYYY-MM-DD

$this->properties["BDAY"] = $date;

}



function setAddress($postoffice="", $extended="", $street="", $city="", $region="", $zip="", $country="", $type="HOME;POSTAL") {

// $type may be DOM | INTL | POSTAL | PARCEL | HOME | WORK or any combination of these: e.g. "WORK;PARCEL;POSTAL"

$key = "ADR";

if ($type!="") $key.= ";$type";

$key.= ";ENCODING=QUOTED-PRINTABLE";

$this->properties[$key] = encode($name).";".encode($extended).";".encode($street).";".encode($city).";".encode($region).";".encode($zip).";".encode($country);



if ($this->properties["LABEL;$type;ENCODING=QUOTED-PRINTABLE"] == "") {

//$this->setLabel($postoffice, $extended, $street, $city, $region, $zip, $country, $type);

}

}



function setLabel($postoffice="", $extended="", $street="", $city="", $region="", $zip="", $country="", $type="HOME;POSTAL") {

$label = "";

if ($postoffice!="") $label.= "$postoffice\r\n";

if ($extended!="") $label.= "$extended\r\n";

if ($street!="") $label.= "$street\r\n";

if ($zip!="") $label.= "$zip ";

if ($city!="") $label.= "$city\r\n";

if ($region!="") $label.= "$region\r\n";

if ($country!="") $country.= "$country\r\n";



$this->properties["LABEL;$type;ENCODING=QUOTED-PRINTABLE"] = quoted_printable_encode($label);

}



function setEmail($address) {

$this->properties["EMAIL;INTERNET"] = $address;

}



function setNote($note) {

$this->properties["NOTE;ENCODING=QUOTED-PRINTABLE"] = quoted_printable_encode($note);

}



function setURL($url, $type="") {

// $type may be WORK | HOME

$key = "URL";

if ($type!="") $key.= ";$type";

$this->properties[$key] = $url;

}



function getVCard() {

$text = "BEGIN:VCARD\r\n";

$text.= "VERSION:2.1\r\n";

foreach($this->properties as $key => $value) {

$text.= "$key:$value\r\n";

}

$text.= "REV:".date("Y-m-d")."T".date("H:i:s")."Z\r\n";

//$text.= "MAILER:PHP vCard class\r\n";

$text.= "END:VCARD\r\n";

return $text;

}



function getFileName() {

return $this->filename;

}

}





// USAGE EXAMPLE

/*

$v = new vCard();



$v->setPhoneNumber("+49 23 456789", "PREF;HOME;VOICE");

$v->setName("Mustermann", "Thomas", "", "Herr");

$v->setBirthday("1960-07-31");

$v->setAddress("", "", "Musterstrasse 20", "Musterstadt", "", "98765", "Deutschland");

$v->setEmail("thomas.mustermann@thomas-mustermann.de");

$v->setNote("You can take some notes here.\r\nMultiple lines are supported via \\r\\n.");

$v->setURL("http://www.thomas-mustermann.de", "WORK");



$output = $v->getVCard();

$filename = $v->getFileName();



Header("Content-Disposition: attachment; filename=$filename");

Header("Content-Length: ".strlen($output));

Header("Connection: close");

Header("Content-Type: text/x-vCard; name=$filename");



echo $output;*/

?>


Next is the FDF creator (fdf.php):

<?php

/*

KOIVI HTML Form to FDF Parser for PHP (C) 2004 Justin Koivisto

Version 2.1.2

Last Modified: 9/12/2005



This library is free software; you can redistribute it and/or modify it

under the terms of the GNU Lesser General Public License as published by

the Free Software Foundation; either version 2.1 of the License, or (at

your option) any later version.



This library is distributed in the hope that it will be useful, but

WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY

or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public

License for more details.



You should have received a copy of the GNU Lesser General Public License

along with this library; if not, write to the Free Software Foundation,

Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA



Full license agreement notice can be found in the LICENSE file contained

within this distribution package.



Justin Koivisto

justin.koivisto@gmail.com

http://koivi.com

*/



/*

* createFDF

*

* Takes values submitted via an HTML form and fills in the corresponding

* fields into an FDF file for use with a PDF file with form fields.

*

* @param $file The pdf file that this form is meant for. Can be either

* a url or a file path.

* @param $info The submitted values in key/value pairs. (eg. $_POST)

* @result Returns the FDF file contents for further processing.

*/

function createFDF($file,$info){

$data="%FDF-1.2\n%????\n1 0 obj\n<< \n/FDF << /Fields [ ";

foreach($info as $field => $val){

if(is_array($val)){

$data.='<</T('.$field.')/V[';

foreach($val as $opt)

$data.='('.trim($opt).')';

$data.=']>>';

}else{

$data.='<</T('.$field.')/V('.trim($val).')>>';

}

}

$data.="] \n/F (".$file.") /ID [ <".md5(time()).">\n] >>".

" \n>> \nendobj\ntrailer\n".

"<<\n/Root 1 0 R \n\n>>\n%%EOF\n";

return $data;

}

?>

There is an official PHP FDF creator, but it uses some ridiculous dll file that you need to install. PHP is great at string manipulation, why the heck do we need a dll? Anyway, thanks a lot Justin Koivisto.

Finally a custom email script I wrote to email multiple attachments (mail_attachment.php):

<?php

function mail_attachment ($from , $to, $subject, $message, $attachments){

$email_from = $from; // Who the email is from

$email_subject = $subject; // The Subject of the email

$email_txt = $message; // Message that the email has in it



$email_to = $to; // Who the email is to

$headers = "From: ".$email_from;


$semi_rand = md5(time());

$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";



$headers .= "\nMIME-Version: 1.0\n" .

"Content-Type: multipart/mixed;\n" .

" boundary=\"{$mime_boundary}\"";



$email_message .= "This is a multi-part message in MIME format.\n\n" .

"--{$mime_boundary}\n" .

"Content-Type:text/html; charset=\"iso-8859-1\"\n" .

"Content-Transfer-Encoding: 7bit\n\n" . $email_txt . "\n\n";



foreach ($attachments as $a) {

$data = chunk_split(base64_encode($a['data']));



$email_message .= "--{$mime_boundary}\n" .

"Content-Type: {$a['mime']};\n" .

" name=\"{$a['filename']}\"\n" .

"Content-Transfer-Encoding: base64\n\n" .

$data . "\n\n";

}



$email_message .= "--{$mime_boundary}--\n";



$ok = @mail($email_to, $email_subject, $email_message, $headers);



if($ok) {

} else {

die("There was a problem sending the email. Please check your inputs.");

}

}



?>



Thank you about.com for the HTML Converter.

Wednesday, January 28, 2009

Howto: Xen Bridging with Static and DHCP NICs

I have been meaning to figure out how to put Xen virtual machines on different networks for over a year. Every once in a while I would start poking at it, but never could get it to work. Now a project I'm doing requires VMs on different networks, and to easily be able to switch them, so I finally took the time to learn. Notably it is more linux networking 101 than anything.

This would have been relatively easy if both NICs used static IPs, this tutorial would have worked more or less out of the box. It turns out that throwing dhcp in the mix really screws with routing and dns. Even worse the dhcp daemon running in the background keeps screwing it up unless you disable it.

-------------------------------------------------

Howto:

Note: This is on Ubuntu 8.04 and Xen 3.2. I want dom0 to access the internet via a static ip on eth0.

First create /etc/xen/scripts/multi-network-bridge then put the following in it:


#!/bin/sh
/etc/xen/scripts/network-bridge $@ vifnum=1 netdev=eth1 bridge=xenbr1
/etc/xen/scripts/network-bridge $@ vifnum=0 netdev=eth0 bridge=xenbr0

ifconfig xenbr1 up
ifconfig xenbr0 up
ip route flush table main
ip route add X.X.X.X/X dev xenbr0
ip route add default via X.X.X.X
cp /etc/resolv.conf.bak /etc/resolv.conf


Where X.X.X.X/X is your static network such as 192.168.1.0/24 and X.X.X.X is your static gateway (192.168.1.1). /etc/resolv.conf.bak is a copy of your static dns servers.

Now make the script executable and disable the dhcp daemon:


sudo chmod +x /etc/xen/scripts/multi-network-bridge
sudo update-rc.d -f dhcdbd remove


Finally, find the line in /etc/xen/xend-config.spx that has "(network-script network-bridge)" and change it to "(network-script multi-network-bridge)".

Now check to make sure that /etc/network/interfaces is configured properly, mine looks like:


auto lo
iface lo inet loopback

auto eth1
iface eth1 inet dhcp

auto eth0
iface eth0 inet static
address x.x.x.x
gateway x.x.x.x
netmask x.x.x.x



For DomUs to use the bridge you need to change the cfg file to look like:

vif = [ 'mac=xx:xx:xx:xx:xx:xx,ip=x.x.x.x,bridge=xenbr0' ]

For the static network, or:


dhcp = 'dhcp'
vif = [ 'mac=xx:xx:xx:xx:xx:xx,bridge=xenbr1' ]

For the dhcp network.


Reboot Dom0 to make sure that networking comes back right.

------------------------------------------------

If you don't specifically name the bridges, then they will automatically be named eth0 and eth1 (and you probably won't have to do the ifconfig xxxx up either). This makes the output of ifconfig look slightly more normal.

A couple other things I found out along the way:

1. The interfaces should already be up and configured properly (with ips) before the bridge script is run. This should happen automatically if /etc/network/interfaces is set up properly.

2. Dom0 connects to the bridge directly, which is why it has an ip assigned.

3. "ip route" and "brctl show" are your friends.

4. The tapX devices are from hardware virtual machines.


Note: Doing this can confuse firefox in to thinking it is offline. If you have issues with firefox make sure File->Work Offline is unchecked (sometimes checking it then unchecking it helps).


Update:

Here is my new multi-network-bridge script:


#!/bin/sh
/etc/xen/scripts/network-bridge $@ vifnum=1 netdev=eth1
/etc/xen/scripts/network-bridge $@ vifnum=0 netdev=eth0

ip route flush table main
ip route add X/X dev eth0
ip route add default via X
cp /etc/resolv.conf.bak /etc/resolv.conf


If you don't specify a bridge then it defaults to eth0.