1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.apache.directory.server.dhcp.io;
22
23
24 import java.io.UnsupportedEncodingException;
25 import java.net.InetAddress;
26 import java.net.UnknownHostException;
27 import java.nio.ByteBuffer;
28 import java.util.Arrays;
29
30 import org.apache.directory.server.dhcp.DhcpException;
31 import org.apache.directory.server.dhcp.messages.DhcpMessage;
32 import org.apache.directory.server.dhcp.messages.HardwareAddress;
33 import org.apache.directory.server.dhcp.options.DhcpOption;
34 import org.apache.directory.server.dhcp.options.OptionsField;
35 import org.apache.directory.server.dhcp.options.dhcp.DhcpMessageType;
36 import org.apache.directory.server.dhcp.options.dhcp.UnrecognizedOption;
37
38
39
40
41
42
43 public class DhcpMessageDecoder
44 {
45
46
47
48
49
50
51
52
53 public DhcpMessage decode( ByteBuffer buffer ) throws DhcpException
54 {
55 byte op = buffer.get();
56
57 short htype = ( short ) ( buffer.get() & 0xff );
58 short hlen = ( short ) ( buffer.get() & 0xff );
59 short hops = ( short ) ( buffer.get() & 0xff );
60 int xid = buffer.getInt();
61 int secs = buffer.getShort() & 0xffff;
62 short flags = buffer.getShort();
63
64 InetAddress ciaddr = decodeAddress( buffer );
65 InetAddress yiaddr = decodeAddress( buffer );
66 InetAddress siaddr = decodeAddress( buffer );
67 InetAddress giaddr = decodeAddress( buffer );
68
69 byte[] chaddr = decodeBytes( buffer, 16 );
70
71 String sname = decodeString( buffer, 64 );
72 String file = decodeString( buffer, 128 );
73
74 OptionsField options = decodeOptions( buffer );
75
76
77 DhcpMessageType mto = ( DhcpMessageType ) options.get( DhcpMessageType.class );
78
79 return new DhcpMessage( null != mto ? mto.getType() : null, op, new HardwareAddress( htype, hlen, chaddr ),
80 hops, xid, secs, flags, ciaddr, yiaddr, siaddr, giaddr, sname, file, options );
81 }
82
83
84
85
86
87
88
89 private static byte[] decodeBytes( ByteBuffer buffer, int len )
90 {
91 byte[] bytes = new byte[len];
92 buffer.get( bytes );
93 return bytes;
94 }
95
96
97
98
99
100
101 private static String decodeString( ByteBuffer buffer, int len )
102 {
103 byte[] bytes = new byte[len];
104 buffer.get( bytes );
105
106
107 int slen = 0;
108 while ( bytes[slen] != 0 )
109 slen++;
110
111 try
112 {
113 return new String( bytes, 0, slen, "ASCII" );
114 }
115 catch ( UnsupportedEncodingException e )
116 {
117 throw new RuntimeException( "No ASCII encoding", e );
118 }
119 }
120
121
122
123
124
125
126
127
128
129 private static InetAddress decodeAddress( ByteBuffer buffer )
130 {
131 byte[] addr = new byte[4];
132 buffer.get( addr );
133 try
134 {
135 return InetAddress.getByAddress( addr );
136 }
137 catch ( UnknownHostException e )
138 {
139
140 return null;
141 }
142 }
143
144 private static final byte[] VENDOR_MAGIC_COOKIE =
145 { ( byte ) 99, ( byte ) 130, ( byte ) 83, ( byte ) 99 };
146
147
148 public OptionsField decodeOptions( ByteBuffer message ) throws DhcpException
149 {
150 byte[] magicCookie = new byte[4];
151 message.get( magicCookie );
152
153 if ( !Arrays.equals( VENDOR_MAGIC_COOKIE, magicCookie ) )
154 {
155 throw new DhcpException( "Parse exception." );
156 }
157
158 byte code;
159 byte length;
160 byte value[];
161
162 OptionsField options = new OptionsField();
163
164 while ( true )
165 {
166 code = message.get();
167 if ( code == 0 )
168 continue;
169
170 if ( code == -1 )
171 break;
172
173 length = message.get();
174 value = new byte[length];
175 message.get( value );
176
177 options.add( getOptionInstance( code, value ) );
178 }
179
180 return options;
181 }
182
183
184 private DhcpOption getOptionInstance( int tag, byte[] value ) throws DhcpException
185 {
186 try
187 {
188 Class c = DhcpOption.getClassByTag( tag );
189
190 DhcpOption o = null != c ? ( DhcpOption ) c.newInstance() : new UnrecognizedOption( ( byte ) tag );
191 o.setData( value );
192
193 return o;
194 }
195 catch ( Exception e )
196 {
197 throw new DhcpException( "Can't set option value: " + e.toString() );
198 }
199 }
200 }