SSブログ

「オープンソースハードウェアセミナーVol1」レポート Arduino host by name ライブラリ こっそり公開 [ATmarquino Arduino]

※C++に関しては全く自信が無い。もっと上手な書き方があると思うけれど。知っていたら教えてね。
あと、PROGMEMはやっぱり面倒くさい。
Img_1427.jpg勿論これを動かす為には、既に公開しているUDPライブラリも一緒に用意しておく必要があります。

※追記!以下のネットワーク設定の特殊事情に付いて。
家のネットワークは、通常のネットワークグループの下にネットワークの実験用のネットワークグループが有って、そことはルーターで区切ってあります。今回は192.168.1.0/24にArduino+Ethernet Shieldを設置しているので、このネットワークグループのデフォルトゲートウエイが192.168.1.1になっています。
また、通常ブロードバンド回線の出入り口にはブロードバンドルーターがあるかと思いますが、プライマリDNSはこのルーターとなるので、まず最初の問合せ先が192.168.100.1となっております。
const byte sip[] = { 192, 168, 1, 177 };
const byte gateway[] = { 192, 168, 1, 1 };
const byte Pri_DNS[] = { 192, 168, 100, 1 };




※ご利用は自由ですが、著作権表示の削除、改竄はできません。
Dns.cpp
/* ------------------------------------------------------------------------ */
/*  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 <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <wiring.h>
#include <Ethernet.h>
#include <Udp.h>
#include <avr/pgmspace.h>

#include "Dns.h"

byte _dnsip[4];
Udp udp = Udp();

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

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

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

Dns::Dns( const byte addr[] )
{
  memcpy( _dnsip, addr, LENGTHIPV4 );
}

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

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

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

  /* FLAG~ドメイン名以前の設定 */
//  memcpy( &buff[2], head_qa, sizeof( head_qa));
  memcpy_P( &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) );
  memcpy_P( &buff[i], tail_qa, sizeof( tail_qa) );

  return i + sizeof( tail_qa );
}

int Dns::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 Dns::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 *)_dnsip, 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/     */
/* ------------------------------------------------------------------------ */


Dns.h
#ifndef  Dns_h
#define  Dns_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に失敗  */

typedef  uint8_t  byte;

class Dns
{
private:
  byte _dnsip[];
  int getaddr_from_pkt( int qid, byte buff[], byte addr[] );
  int setup_query_pkt( const char *dname, byte buff[] );
public:
  Dns( const byte addr[] );
  int getaddrbydns( const char *dname, byte addr[] );
};
#endif


sampleスケッチ
#include <Ethernet.h>
#include <Dns.h>

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

Dns dns = Dns( Pri_DNS );

void setup()
{
  int result;
  byte dip[4];

  delay( 1000 );
  Ethernet.begin( (uint8_t *)mac, (uint8_t *)sip, (uint8_t *)gateway );
  Serial.begin( 38400 );
  delay( 3000 );

  if( (result = dns.getaddrbydns( query_hamayan_name, dip )) == 0 )
  {
    Serial.print( "IP Adr=" );
    Serial.print( dip[0], DEC );
    Serial.print( '.' );
    Serial.print( dip[1], DEC );
    Serial.print( '.' );
    Serial.print( dip[2], DEC );
    Serial.print( '.' );
    Serial.print( dip[3], DEC );
    Serial.println();
  }
  else
  {
    Serial.print( "NG1 type=" );
    Serial.println( result, DEC );
  }

  if( (result = dns.getaddrbydns( query_google_name, dip )) == 0 )
  {
    Serial.print( "IP Adr=" );
    Serial.print( dip[0], DEC );
    Serial.print( '.' );
    Serial.print( dip[1], DEC );
    Serial.print( '.' );
    Serial.print( dip[2], DEC );
    Serial.print( '.' );
    Serial.print( dip[3], DEC );
    Serial.println();
  }
  else
  {
    Serial.print( "NG2 type=" );
    Serial.println( result, DEC );
  }
}

void loop()
{
}


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

nice! 0

コメント 0

コメントを書く

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

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

トラックバック 0

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