1

While building a basic Windows Image deployment solution (using WinPE and custom applications built in C#), I came across a problem of 2 Computers not being on the same subnet/IP segment (no static IP Address or DHCP Servers & DNS/Routing tables). To combat this I have written a basic but successful DHCP solution and extended it to TFTP for remote boot in C#.

This application was implemented using guidance in RFCs 1350, 4578, and has the beginnings of negotiation referenced in RFC 2347. I have managed to write a routine that sends the requested files to the remote application.

I have utilized the Wireshark application to examine my outgoing messages, and found that the DHCPOFFER and DHCPACK responses were malformed. These have been corrected, but leaving me with an issue with the TFTP implementation.

The client machine is requesting the provided boot file name, but appending extra bytes to the name before the 0 byte signifying the end of the file name string. Please see below excerpt from my code for extracting the file name from the TFTP Read Request (RRQ) message:

switch(datagram[1]) //position of OpCode Indicator
{
        case (byte)TFTP_OpCode.RRQ
        {
            TidPort = new Random();
            var port = TidPort.New(65200, 65350); // Server TX ID & Port
            offset = offset + 1;
            int strlength = 0;
            while (datagram[offset] != (byte)0)
            {
                strlengeth++;
                offset++
            }
            byte[] tmpbytes = new byte[strlength -1];
            Array.Copy(datagram, 2, tmpbytes, 0, strlength -1)
        }
}

Where 'datagram' is a byte array received using a UDP Socket.

Code for converting the string to byte array to pass in the DHCPOFFER/ACK message:

switch (option)
    {
        case BOOTFILE:
            {
            byte[] tmpbytes = new byte[Encoding.ASCII.GetByteCount("pxeboot.n12")];
            tmpbytes = Encoding.ASCII.GetBytes("pxeboot.n12");
            _totalLength = tmpbytes.Length + 2;
            _option = new byte[_totalLength];
            _option[0] = (byte)BOOTFILE;
            _option[1] = (byte)tmpbytes.Length;
            Array.Copy(tmpbytes, 0, _option, 2, tmpbytes.Length);
            Array.Copy(_option, 0, result, optionPosition, _option.Length);
            optionPosition = optionPosition + _totalLength;
            break;
            }
    }

when using Encoding.ASCII.getString(tmpbytes[]) in console.WriteLine(), I ampresented with 'pxeboot.n12?'. Pre Wireshark and messaging correction, I was able to correctly extract the boot file name (in this case pxeboot.n12) from the TFTP RRQ, but it would fail on TFTP request for the BCD file (located in "Boot\BCD").

When I am able to extract the filename correctly (every file, every time), is there any other options that I should be passing back (i.e. option 93, 94 and 97 (System Architecture, Network ID version, UUID/GUID) or option 253 (noticed in Wireshark using another DHCP/TFTP solution)?

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
  • FTP has a text and binary mode. Make sure when sending binary you use binary mode. The only time you need to use text mode is when you are transferring data between systems that use a different return character. When in text mode it will automatically correct the return character for you operating system. – jdweng Feb 21 '19 at 13:42
  • Can you expand/explain a little more please? I'm using ASCII for both encoding and to bytes and from bytes. From RFC 1350, the filename is returned in NVTASCII (a subset of ASCII?) terminated with a zero (0). – R.McInnes-Piper Feb 21 '19 at 13:50
  • First RFC 1350 is using Base 64 string (in unix/ultrix what use to be uuencode and uudecode). Depending on the language ASCII encoding may not work. You may need to use one of the Windows Encoding like 1252. Ascii is for character 0 to 127. The characters from 127 to 255 may be mapped differently depending on the Language like Latin, or Russian. I wouldn't call NVTASCII a subset of ascii, instead a type of ascii since only characters 127 to 255 are different. I would use UTF8 encoding instead of ASCII. Ascii encoding removes non printable charcters. – jdweng Feb 21 '19 at 14:05
  • @jdweng, I have tried both UTF-8 and UTF-7 in quite a few combinations between ASCII and UTF-8/7. Still a failure. If i Encoding.ASCII on the entire byte array, the file name presents true with no extra characters – R.McInnes-Piper Feb 21 '19 at 15:39
  • You should not be using any encoding on the binary data. You should be using : string Convert.ToBase64String(byte[]). The file name you may need encoding. – jdweng Feb 21 '19 at 17:55
  • @jdweng, Sorry for the late reply - Night Shift can be a pain. I have tried using Convert.ToBase64String() - it didn't return anything usable. I utilized the below method to strip the unwanted character. – R.McInnes-Piper Mar 01 '19 at 00:29
  • I should of said FTP does the Convert automatically. You shouldn't have to strip characters. If you have binary data it will corrupt the data making changes like that. You should be able to specify BINARY mode so you do not need to change the data. – jdweng Mar 01 '19 at 09:53

1 Answers1

0

I have had to utilize the string.SubString() method:

string filestring = Encoding.ASCII.GetString(tmpbytes); int pos = filestring.IndexOf("?"); filestring = filstring.SubString(0, pos-1);

to remove the unwanted character from tmpbytes array.

Options 93, 94 & 97 are now passed back in the DHCPOFFER message post options requested. Both DHCP and TFTP implementation now working as expected.