SSブログ

「オープンソースハードウェアセミナーVol1」レポート Arduino Ethernet Shieldでインターネットから名前を引こう DNSの実現 [ATmarquino Arduino]

しまった。「名前を引こう!」では逆引きみたいだな。
ether_shield_014.png
ether_shield_015.png
結構この機能欲しい人も多い筈!。

元々DNSの正引き機能は、HOS上にプロトコルスタックを載せたNavajoのUDPアプリケーションの一つとして、HOSの開発メンバーであるm-arai氏に作ってもらい、その後Project-HOSの著作物となったものです。
それをArduino用に載せ換えました。
なので、このプログラムの二次利用は自由ですが、著作権表示の削除や改竄はしないでくださいね。

今回UDPの機能を実現したのでやってみました。スケッチは下の方に掲載して置きます。

上の図はDOS窓からnslookupを行って正引きを行った結果です。
下は勿論Arduino上で実行した結果です。
ね!、引けているでしょう。
今までこのDNS正引きを使った感触ですが、結構引けます。でも完全に引ける訳ではないのも事実です。
その辺に注意して使ってね。



/* ------------------------------------------------------------------------ */
/*  Hyper Operating System V4                               */
/*	test program for Navajo                               */
/*	お題: いい加減なDNS IPアドレス正引き         */
/*                                                                          */
/*	このプログラムは、m-arai氏の好意で、Project HOSの著作物となりました。 */
/*                                  Copyright (C) 1998-2004 by Project HOS  */
/*                                  http://sourceforge.jp/projects/hos/     */
/* ------------------------------------------------------------------------ */
#include <Ethernet.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>

#define  DNS_PSIZE   512
#define  DNS_PORT    53
#define  LENGTHIPV4  4

#define  E_LONG     (-1)  /* ドメイン名が長過ぎる */
#define  E_BADID    (-2)  /* 回答のIDが違う */
#define  E_BADHD    (-3)  /* 回答のヘッダ部が正常でない */
#define  E_SNDFAIL  (-4)  /* なんか知らんがUDPsendに失敗  */
#define  E_SCKFAIL  (-5)  /* なんか知らんがUDPsocketに失敗  */

const byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const byte ip[] = { 192, 168, 100, 177 };
const byte gateway[] = { 192, 168, 100, 1 };
const byte DomainNameServer[] = { 192, 168, 100, 1 };
const char query_hamayan_name[] = "hamayan.ddo.jp";
const char query_google_name[] = "google.com";

static const byte head_qa[] =
{
  0x01,0x00, /* 再帰照会 */
  0x00,0x01, /* 質問数 1 */
  0x00,0x00, /* 回答数 */
  0x00,0x00, /* 権威 */
  0x00,0x00 /* 追加 */
}; 

static const byte tail_qa[] =
{
  0x00,		/* ドメイン名終端 */
  0x00,0x01,	/* type  A */
  0x00,0x01	/* class INET */
}; 

static const byte repl_head[] =
{
  0x81, 0x00,	/* FLAG: 回答,再帰照会 */
  0x00, 0x01,	/* Qnum: 質問数 1 */
  0x00, 0x01,	/* Anum: 回答数 1 */
  0x00, 0x00,	/* 権威: 0 */
  0x00, 0x00,	/* 追加: 0 */
};

static int id;

Udp udp = Udp();  /*UDP socketの生成*/

void setup()
{
  byte addr[4];

  Ethernet.begin( (uint8_t *)mac, (uint8_t *)ip, (uint8_t *)gateway );

  Serial.begin( 38400 );

  delay( 3000 );  /*シリアルモニタへの切り替え時間分、待ちを入れてある*/

  getaddrbydns( query_hamayan_name, addr );

  Serial.print( "ip=" );
  for( int i = 0; i < sizeof(addr) / sizeof(addr[0]); i++ )
  {
    Serial.print( addr[i], DEC );
    Serial.print( "." );
  }
  Serial.println();

  delay( 100 );
  getaddrbydns( query_google_name, addr );

  Serial.print( "ip=" );
  for( int i = 0; i < sizeof(addr) / sizeof(addr[0]); i++ )
  {
    Serial.print( addr[i], DEC );
    Serial.print( "." );
  }
  Serial.println();
}

void loop()
{
}

/* DNS Aの問い合わせパケットを作成する
   返り値はパケットサイズあるいは負のエラーコード */
int setup_query_pkt( const char *dname, byte buff[] )
{
  const char *p,*q;
  int  i,len,lid;

  /* idをユニークに */
  lid = id++;

  /* ID設定 */
  buff[0] = (lid >> 8) & 0xff;
  buff[1] = lid & 0xff;

  /* FLAG~ドメイン名以前の設定 */
  memcpy( &buff[2], head_qa, sizeof( head_qa));

  for( i = 12, p = dname;*p != '\0'; i += len, p = q + 1 )
  {
    /* 次の'.'又は文末の検索 */
    for( q = p; *q != '.' && *q != '\0'; q++ ) ;

    /* パケット溢れチェック */
    if( (len = q-p)+i > DNS_PSIZE-5)
    {
      return E_LONG;
    }

    buff[i++] = len;

    /* 文字列コピー */
    strncpy( (char *)&buff[i], p, len);

    if (*q=='\0')
    {
      i += len;
      break;
    }
  }

  /* ドメイン名終端~パケット終了の設定 */
  memcpy( &buff[i], tail_qa, sizeof( tail_qa) );

  return i + sizeof( tail_qa );
}

int getaddr_from_pkt( int qid, byte buff[], byte addr[] )
{
  int i;

  /* 回答のIDが合致しているかチェック */
  if( qid != ((buff[0] << 8) + buff[1]) )
  {
    return E_BADID;
  }

  /* ヘッダ部が正常回答がチェック  2009/6/8 修正:一つの質問に複数の回答があるケースに対応させる為*/
  if( ((buff[2] & 0xfb) != 0x81) || ((buff[3] & 0x0f) != 0)
      || ((buff[4] << 8) + buff[5]) != 1 )
  {
    return E_BADHD;
  }

  /* ドメインの終端を探す */
  for( i = 12; buff[i] != '\0'; i++ ) ;

  /* もうこの後,回答のタイプは一切チェックしない */

  if( ( buff[i+5] & 0xc0) == 0xc0 )
  {
    /* ドメインは圧縮されている */
    memcpy( addr, &buff[ i + 17], LENGTHIPV4 );
  }
  else
  {
    /* 多分有り得ないが,圧縮されていない */
    /* ドメイン終端を検索 */
    for( i = i + 6; buff[i] != '\0'; i++ ) ;
    memcpy( addr, &buff[i + 11], LENGTHIPV4 );
  }

  return 0;
}

int getaddrbydns( const char *dname, byte addr[] )
{
  int  ssz,ret,qid;
  byte server_ip[4];
  uint16 dport;
  byte *buff;

  /*UDPソケットOPEN*/
  if( !udp.Open() ) return E_SCKFAIL;

  /* 共有メモリからDNSパケットバッファ用メモリを取得 */
  buff = (byte *)malloc( DNS_PSIZE );

  /* DNS A問い合わせパケット作成 */
  ssz = setup_query_pkt( dname, buff);
  qid = ( buff[0] << 8 ) + buff[1];

  /* パケット送信 */
  udp.sendTo( (const uint8 *)buff, ssz, (uint8 *)DomainNameServer, DNS_PORT );
  delay( 100 );
  while( udp.recvFrom( (uint8 *)buff, DNS_PSIZE, (uint8 *)server_ip, &dport ) == (-1) ) delay( 10 );

  /* 回答からIPアドレスを取得する */
  ret = getaddr_from_pkt( qid, buff, (byte *)addr );

  /* DNSパケットバッファ用メモリを解放 */
  free( buff );

  /*ソケットのクローズ*/
  udp.Close();

  return ret;
}

/* ------------------------------------------------------------------------ */
/*                                  Copyright (C) 1998-2004 by Project HOS  */
/*                                  http://sourceforge.jp/projects/hos/     */
/* ------------------------------------------------------------------------ */


Arduinoモニタープログラム参加中
電子部品・半導体の通販サイト - チップワンストップ



マスタリングTCP/IP 入門編 第4版

マスタリングTCP/IP 入門編 第4版

  • 作者: 竹下 隆史
  • 出版社/メーカー: オーム社
  • 発売日: 2007/02/24
  • メディア: 大型本



TCP/IPの絵本 ネットワークっておもしろい!

TCP/IPの絵本 ネットワークっておもしろい!

  • 作者: アンク
  • 出版社/メーカー: 翔泳社
  • 発売日: 2003/12/13
  • メディア: 単行本



nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:[必須]
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。