// コンストラクタ // その他のパケットをベースに作成 public DhcpPacket(DhcpPacket basePacket, DhcpPacket.MessageType message_type, DhcpLeases dhcplease) : this() { if (message_type == MessageType.DHCPOFFER) { BuildDHCPOFFER(basePacket, dhcplease); } if (message_type == MessageType.DHCPACK) { BuildDHCPACK(basePacket, dhcplease); } }
// UDP送信 private void SendUDP(IPAddress sourceIPAddress, int sourcePort, IPAddress remoteIPAddress, int remotePort) { // 送信元 var localEP = new IPEndPoint(sourceIPAddress, sourcePort); // 送信先 var remoteEP = new IPEndPoint(remoteIPAddress, remotePort); // 送信データ DhcpPacket rcv_packet = new DhcpPacket(this.lastRcvBytes_); DhcpPacket.MessageType snd_message_type = (rcv_packet.message_type_ == DhcpPacket.MessageType.DHCPDISCOVER)? DhcpPacket.MessageType.DHCPOFFER: (rcv_packet.message_type_ == DhcpPacket.MessageType.DHCPREQUEST)? DhcpPacket.MessageType.DHCPACK: DhcpPacket.MessageType.unknown; if (snd_message_type == DhcpPacket.MessageType.unknown) { return; } DhcpPacket snd_packet = new DhcpPacket(rcv_packet, snd_message_type, this.dhcplease_); byte[] msg = snd_packet.GetPacketBytes(); //データを文字列に変換する string rcvMsg = "0x" + snd_packet.xid_.ToString("X4") + ", " + snd_packet.message_type_; //送信したデータの情報をRichTextBoxに表示する string displayMsg = string.Format("{0} [{1} ({2})] > {3}", DateTime.Now.ToString("HH:mm:ss.fff"), remoteEP.Address, remoteEP.Port, rcvMsg); textBoxRcvData.BeginInvoke( new Action <string>(ShowReceivedString), displayMsg); // 送信イベントデータ var ev = new SocketAsyncEventArgs(); ev.RemoteEndPoint = remoteEP; ev.SetBuffer(msg, 0, msg.Length); // UDP送信 var socket = new Socket(SocketType.Dgram, ProtocolType.Udp); socket.Bind(localEP); // bindしたIP、ポートと異なる送信元としたい(場合がある)のでudpClient_は使用しない socket.SendToAsync(ev); // 非同期で送信 socket.Shutdown(SocketShutdown.Both); socket.Close(); }
private void BuildDHCPACK(DhcpPacket basePacket, DhcpLeases dhcplease) { DhcpLeaseItem item = dhcplease.GetItem(basePacket.chaddr_); this.op_ = OP.BOOTREPLY; this.htype_ = basePacket.htype_; this.hlen_ = basePacket.hlen_; this.xid_ = basePacket.xid_; this.ciaddr_ = basePacket.ciaddr_; this.yiaddr_ = item.yiaddr_; this.siaddr_ = new IPAddress(0); // 仮 this.giaddr_ = basePacket.giaddr_; this.chaddr_ = basePacket.chaddr_; this.options_ = new DhcpOptions( DhcpPacket.MessageType.DHCPACK, basePacket.chaddr_, basePacket.dhcpoption55_, dhcplease ); }
// 送信パケットを作成 public byte[] GetPacketBytes() { List <byte> list = new List <byte>(); DhcpPacket.addBigEndian(ref list, (byte)(this.op_)); DhcpPacket.addBigEndian(ref list, this.htype_); DhcpPacket.addBigEndian(ref list, this.hlen_); DhcpPacket.addBigEndian(ref list, (byte)0); // hops DhcpPacket.addBigEndian(ref list, this.xid_); DhcpPacket.addBigEndian(ref list, (UInt16)0); // secs DhcpPacket.addBigEndian(ref list, (UInt16)0x8000); // flags // 決め打ち DhcpPacket.addBigEndian(ref list, this.ciaddr_); DhcpPacket.addBigEndian(ref list, this.yiaddr_); DhcpPacket.addBigEndian(ref list, this.siaddr_); DhcpPacket.addBigEndian(ref list, this.giaddr_); DhcpPacket.addBigEndian(ref list, this.chaddr_); list.AddRange(new byte[64 + 128]); // sname, file list.AddRange(this.options_.GetPacketBytes()); // options return(list.ToArray()); }
//データを受信した時 private void ReceiveCallback(IAsyncResult ar) { System.Net.Sockets.UdpClient udp = (System.Net.Sockets.UdpClient)ar.AsyncState; //非同期受信を終了する System.Net.IPEndPoint remoteEP = null; byte[] rcvBytes; try { rcvBytes = udp.EndReceive(ar, ref remoteEP); } catch (System.Net.Sockets.SocketException ex) { Console.WriteLine("受信エラー({0}/{1})", ex.Message, ex.ErrorCode); return; } catch (ObjectDisposedException ex) { //すでに閉じている時は終了 Console.WriteLine("Socketは閉じられています。"); return; } // 処理対象? DhcpPacket rcv_packet = new DhcpPacket(rcvBytes); Boolean reply = this.dhcplease_.AutoReply(rcv_packet.chaddr_); Boolean match = this.dhcplease_.Matches(rcv_packet.chaddr_); { // 受信情報を控えておく(送信データに載せるため) // 受信データ lastRcvBytes_ = new byte[rcvBytes.Length]; Array.Copy(rcvBytes, 0, lastRcvBytes_, 0, rcvBytes.Length); // 受信元 lastRemoteEP_ = remoteEP; } //データを文字列に変換する string rcvMsg = "0x" + rcv_packet.xid_.ToString("X4") + ", " + rcv_packet.message_type_; //受信したデータと送信者の情報をRichTextBoxに表示する string displayMsg = string.Format("{0} [{1} ({2})] < {3}", DateTime.Now.ToString("HH:mm:ss.fff"), remoteEP.Address, remoteEP.Port, rcvMsg); textBoxRcvData.BeginInvoke( new Action <string>(ShowReceivedString), displayMsg); // 応答する if (match && (!reply)) { // 当該MACアドレスが登録されていて、 // かつ、「自動応答」が明示的にOFFされている場合は応答しない } else { // それ以外は応答する // 送信先のIPアドレスは remoteEP.Address ではなく、ブロードキャスト SendUDP(sourceIPAddress_, sourcePort_, IPAddress.Broadcast, remoteEP.Port); } //再びデータ受信を開始する udp.BeginReceive(ReceiveCallback, udp); }