IPv6とIPv4を判別してWebサイトに表示する方法【Connected via画像】

未分類

よくKDDIやIIJのサイトで右上に「Connected via IPv4」とか「Connected via IPv6」という表記がされています。

閲覧した人の利用するIPのバージョンを判別して、画像を表示しているこの仕組ですが、本サイトでもやってみました。その方法を紹介します。

IPv6とIPv4を判別してWebサイトに表示する方法

本サイトでは、Cloudflareを利用しているので、Cloudflare Workersを用いて実装しました。

Workerのエンドポイントであるhttps://monolithon.net/cdn-api/v1/ip-badgeをGETすると、接続に使われたIPのバージョンを判別して、適切な画像を返す仕組みです。

コードはこちら。別途Base64エンコードした画像データをご用意ください。

addEventListener("fetch", event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  const remoteIP = request.headers.get('CF-Connecting-IP')
  let imgBuf;
  if (remoteIP.match(ipv4RegEx)) {
    imgBuf = atob(ipv4img) 
  } else {
    imgBuf = atob(ipv6img)
  }
  const len = imgBuf.length
  let bytes = new Uint8Array(len);
  for (let i = 0; i < len; i++) {
    bytes[i] = imgBuf.charCodeAt(i);
  }
  headers.append('Expires', new Date(Date.now() + 60000).toUTCString())
  return new Response(bytes.buffer, {headers})
}

const ipv4RegEx = /^((25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])\.){3}(25[0-5]|2[0-4][0-9]|1[0-9][0-9]|[1-9]?[0-9])$/
const headers = new Headers()
headers.append('Content-Type', 'image/jpeg')

const ipv4img = 'Your base64-encoded image'
const ipv6img = 'Your base64-encoded image'

Base64エンコードした画像データをipv4imgとipv6imgという2変数に格納しておき、リクエストごとに、ArrayBufferに変換して送り返すという仕組みです。

サイトには、次のようなHTMLを追加しています。

<img src="/cdn-api/v1/ip-badge" width="140" height="21" loading="lazy">

要は単純に画像を読み込むだけですが、これをページ遷移ごとにやるのは無駄だ。なので、画像は1分間ブラウザにキャッシュするようにしています。

IPv6とIPv4を判別してWebサイトに表示した結果

本サイトをパソコンで見ている方なら気づいたはず。右側のサイドバーの一番上に表示されています。

スマホの方も、下の方にスクロールすると表示されます。ぜひ見てみてください。