アプリケーション層は、OSI参照モデルや5階層TCP/IPモデル、4階層TCP/IPモデルなどで最も上位の層である。
アプリケーション層 |
トランスポート層 |
ネットワーク層 |
データリンク層 |
物理層 |
本稿では、アプリケーション層のいくつかのプロトコルによって実装されるWebや電子メールについて紹介する。
5階層TCP/IPモデルでは、アプリケーション層の各プロトコルはトランスポート層で提供されるポートを利用する。そして、いくつかの有名なプロトコルでは、サーバで利用するポート番号がICANNによって標準化されている。また、それ以外の多くのプロトコルも使用するポート番号が明示されている。
ウェルノウンポート番号(well-known ports) | 0-1023 | ICANNで登録されているポート番号の範囲のうち有名なもの |
登録済みポート番号 | 1024-49151 | ICANNで登録されているポート番号の範囲 |
プライベート(ダイナミック)ポート番号 | 49152-65535 |
ユーザやアプリケーションが自由に利用できるポート番号の範囲。多くの場合、クライアントアプリが必要に応じて動的に使用する。
|
ウェルノウンポート番号(0-1023)
登録済みポート番号(1024-49151)
プライベート(ダイナミック)ポート番号(49152-65535)
多くのプロトコルでは、クライアントアプリケーションが使用するポート番号は、プライベートポート番号の中で使われていないもの無作為に動的に使用する。例えば、WebブラウザでHTTP(80番ポート)のサイトにアクセスする際のパケット解析した結果の一部を示す。
user% tcpdump -n -X dst port 443 -i wlan0
06:29:52.791584 IP 192.168.1.14.60063 > 183.77.202.242.80: Flags
[S], seq 1904628341, win 14600, options [mss 1460,sackOK,TS val
104657554 ecr 0,nop,wscale 4], length 0
この解析後すぐにサーバとクライアントのTCPポートを確認すると、それぞれ次のような結果となる。
- サーバ
uesr% telnet 183.77.202.242 80
Trying 183.77.202.242...
Connected to 183.77.202.242.
Escape character is '^]'.
- クライアント
uesr% telnet localhost 60063
Trying ::1...
Trying 127.0.0.1...
telnet: Unable to connect to remote host: Connection refused
このようにクライアントのポートは、動的に使用される。
また、同じクライアントアプリを起動し直して再度同じページにアクセスしてもクライアントが使用するポート番号が同じであるとは限らない。
user% tcpdump -n -X dst port 443 -i wlan0
06:34:15.218947 IP 192.168.1.14.60082 > 183.77.202.242.80: Flags
[F.], seq 2386135769, ack 94445475, win 2641, options [nop,nop,TS val
104723161 ecr 2033111718], length 0
前の例では、クライアントアプリは60063番ポートを使用したが、今回は60082番ポートを使用している。このように、クライアントアプリは、49152番から65535番のポート番号を動的に使用する。
TCP
トランスポート層のTCPは、高品質なデータ通信を可能にする。アプリケーション層では、これを利用したものがいくつもある。それらはユーザに対して、さまざまなものを提供する。
telnet
telnetコマンドを使用すると、ユーザは簡単にTCPのサービスを受けることができる。telnetは指定したIPアドレスのポート番号に対し、ユーザが入力した文字列を送信する。本稿では、これを利用してHTTPやSMTP、POP3などのプロトコルを説明する。
WWW(World Wide Web)上でテキストや画像などのデータを通信するのに使用されている代表的なプロトコルが、HTTP(Hyper Text Transfer Protocol)である。HTTPサーバは基本的にTCPポートの80番を使用し、クライアントが要求したテキストや画像などを送信する。HTTPクライアントとして最も有名なアプリケーションがWebブラウザである。Webブラウザにはさまざまな種類がある。
- Internet Explorer
- Firefox
- Google Chrome
- Safari
ユーザの中にはWebブラウザが表示したWebページを、Web(HTTP)サーバが提供している画面だと認識しているかもしれない。しかしHTTPクライアントが取得するデータは、基本的にHTML(Hyper Text Markup Language)という形式のテキストである。HTTPのバージョン1.0では、クライアントは次のようにGETメソッドを使用してHTMLテキストを取得できる。
user% telnet pied-piper.net 80
Trying ::1...
Connected to pied-piper.net.
Escape character is '^]'.
GET /index.html HTTP/1.0
HTTP/1.1 200 OK
Date: Mon, 14 Apr 2014 15:34:24 GMT
Server: Apache/2.2.22 (Debian)
Last-Modified: Sat, 21 Sep 2013 17:22:33 GMT
ETag: "6a2c55-b1-4e6e8084eb7e3"
Accept-Ranges: bytes
Content-Length: 177
Vary: Accept-Encoding
Connection: close
Content-Type: text/html; charset=UTF-8
<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added,
yet.</p>
</body></html>
Connection closed by foreign host.
HTTPの仕様についてはRFCを参照されたし。
HTML(Hyper Text Markup Language)
HTTPは基本的にHTMLという形式のテキストを転送する。HTMLはマークアップ言語とよばれるコンピュータ言語の一種である。マークアップ言語はタグという文字列を使って、各文章を意味付けできる。例えば<h1>ハロー</h1>は"ハロー"という文字列が文中の最大レベルの見出しであることを示す。タグは基本的にマークしたい文字列を囲うことで意味付けする。以下にサンプルコードを示す。
<html><body><h1>It works!</h1>
<p>This is the default web page for this server.</p>
<p>The web server software is running but no content has been added,
yet.</p>
</body></html>
- <html>-</html>
- HTMLの文
- <body>-</body>
- 本文
- <h1>-</h1>
- 見出し レベル1-6(1が最大)
- <p>-</p>
- 段落
HTMLレンダリングエンジン
WebブラウザはHTMLを受け取るとそれを読み込み、解釈してユーザに分かりやすい形で表現する。前述で紹介したWebブラウザの場合、HTMLを視覚的に見やすい形で表現する。前述のサンプルを表現した例が次の通りである。
ただし必ずしも視覚的な表現だけとは限らず、視覚障害者用の音声ブラウザのように音声で表現するものもある。このHTMLを取得し、それを解釈してユーザに分かりやすいよう表現するプログラム、または機能をHTMLレンダリングエンジンという。最近のHTMLレンダリングエンジンの多くはHTMLだけでなく、CSS(Cascading Style Sheets)やJavaScriptなどを読み込む機能を持つ。
- CSS(Cascading Style Sheets)
- HTMLの視覚的情報を指定する情報。例えば文字の色や大きさなどがある。
- JavaScript
- 動的なWebサイトを構築するためのプログラミング言語。HTTPのクライアントであるWebブラウザによって読み込まれ、処理される。
HTMLレンダリングエンジンには、次のようなものがある。
HTMLレンダリングエンジン | Webブラウザ |
Trident |
- Internet Explorer
- Sleipnir
- Craving Explorer
|
Gecko |
- Firefox
- Epiphany(後にWebKitに移行)
|
WebKit |
|
HTMLには基本的に視覚的情報がない。また、HTMLレンダリングエンジンによって独自のCSSのプロパティがある。それゆえ、HTMLレンダリングエンジン毎に表示される画面が同じであるとは限らない。
WebKitライブラリ
オープンソースのHTMLレンダリングエンジンであるWebKitを使用したプログラミングのサンプルを以下に示す。
#!/usr/bin/python2.7
import gtk
import webkit
win = gtk.Window()
web = webkit.WebView()
web.open("http://www.google.co.jp")
win.add(web)
win.show_all()
Debian7.10では"python-webkit-dev"というパッケージをインストールすることで、環境を整えることができる。
電子メールとは、コンピュータネットワークを使って、メッセージやファイルなどのデータの送受信を行う手段のこと。電子メールはメールやEメールなどと略される。本稿ではメールと記述する。
メールの機能は、メールサーバとメールクライアントによって実装される。
- メールクライアント
- ユーザはメールクライアントによってメールサービスを受けることができる。メールクライアントの機能は、メールサーバに保存されているメールを受け取ったり、メールサーバに頼んでメールを送ってもらったりする。
- メールサーバ
- メールの転送は各メールサーバが行う。
メールの送信から受信までの流れ
メールの実装にはアプリケーション層のいくつかのプロトコルが使用される。
プロトコル | 機能 | ポート |
POP3(Post Office Protocol version3) | メールサーバからメールを受け取る(POPとIMAPそれぞれに利点と欠点がある)。 | tcp/110 |
IMAP(Internet Message Access Protocol) | tcp/143, tcp/220 |
SMTP(Simple Mail Transfer Protocol) | メールを転送する。 | tcp/25 |
あるユーザがメールを送信し、別のユーザがメールを確認するまでの流れは次の通りである。
メールサーバは、それぞれドメイン(例:pied-piper.net)を持つ。
- メールクライアントはSMTPクライアントとして、自身のドメインのメールサーバのSMTPサーバ機能に対して、送信要求を行う。
- SMTPサーバはメールの宛先が自身のドメインであれば、設定されたメールボックスにそれを追加する。それ以外の場合、その宛先ドメインのメールサーバのSMTPサーバ機能に対し、SMTPクライアントとして送信要求を行う。
- 受信するユーザは、POP3やIMAPクライアントでメールサーバにアクセスすることで、自身宛に届いたメールを受け取ることができる。
電子メールの仕組み
メールは5つのプログラム(機能)によって構成される。以下にそれらのプログラムとメールの流れを紹介する。
- MUA(Mail User Agent)
- いわゆるメールクライアントのこと。他にもメーラ、メールリーダなどと呼ばれる。
- MTA(Mail Transfer Agent)
- メールを別のメールサーバに送信したりMDAに渡したりするもの。
- MDA(Mail Delivery Agent)
- MTAから受け取ったメールをメールボックスに保存するもの。
- MRA(Mail Retrieval Agent)
- メールを受信するもの。
- MSA(Mail Submission Agent)
- MUAとMTAの間で認証などを行うもの。メールの仕組みができたばかりのころはなかったが、現在はセキュリティのためにMSAを間に置くのが主流。
メールクライアント
前述のHTTPのサンプルと同様に、telnetを使ってSMTPとPOP3のサーバにアクセスした例を以下に示す。
- SMTP
user% telnet 192.168.1.101 25
Trying 192.168.1.101...
Connected to versus.
Escape character is '^]'.
220 pied-piper.net ESMTP
HELO pied-piper.net
250 pied-piper.net
MAIL FROM: me@pied-piper.net
250 ok
RCPT TO: user@pied-piper.net
250 ok
DATA
354 go ahead
From: me@pied-piper.net
Subject: test
Hello, User
.
250 ok 1397490184 qp 6800
QUIT
221 pied-piper.net
Connection closed by foreign host.
ちなみにSMTPの通信には,DATA以前に入力した情報を使用し,それ以降はメールヘッダのために使用する。
それゆえヘッダ部分は,偽装することも可能であるが,いくつかのSMTPサーバは,そのような怪しいメールの受け取りを拒否する。
- POP3
user% telnet 192.168.1.101 110
Trying 192.168.1.101...
Connected to versus.
Escape character is '^]'.
+OK <6798.1397490101@pied-piper.net>
USER user
+OK
PASS hogehoge
+OK
STAT
+OK 125 3714019
LIST
+OK
1 754
2 1846
3 782
RETR 1
+OK
Return-Path: <user@pied-piper.net>
Delivered-To: user@pied-piper.net
Received: (qmail 6615 invoked by uid 0); 15 Apr 2014 00:22:33 +0900
Received: from unknown (HELO pied-piper.net) (192.168.1.111)
by 192.168.1.101 with SMTP; 15 Apr 2014 00:22:33 +0900
From: me@pied-piper.net
Subject: test
Hello, User
.
QUIT
+OK
Connection closed by foreign host.
SMTP,POP3プログラミング
SMTPやPOP3ライブラリを使用したサンプルコードを以下に示す。
- SMTP
#!/usr/bin/python2.7
import smtplib,email.utils
from email.mime.text import MIMEText
FROM = "i@pied-piper.net"
TO = "you@example.pied-piper.net"
msg = MIMEText('This is the body of the message.')
msg['To'] = email.utils.formataddr(('You', TO))
msg['From'] = email.utils.formataddr(('O_Messiaen', FROM))
msg['Subject'] = 'Hello'
server = smtplib.SMTP('192.168.1.101', 25)
server.set_debuglevel(True) # show communication with the server
try:
server.sendmail(FROM, [TO], msg.as_string())
finally:
server.quit()
- POP3
#!/usr/bin/python2.7
import poplib
pop3 = poplib.POP3("192.168.1.201", 110)
pop3.user("user")
pop3.pass_("hogehoge")
retr = pop3.retr(len(pop3.list()[1]))
"\n".join(retr[1])
OSI参照モデル(7階層モデル)では,アプリケーション層とトランスポート層の間に,プレゼンテーション層とセッション層がある。セッション層では,通信の開始時や終了時などに送受信するデータの形式などを規定する。セッション層には例えばSSL(Secure Socket Layer)がある。SSLの詳細は省略するが,それは階層の上位のレイヤに対して暗号化や認証,完全性を提供する。昨今,httpやsmtp,pop3などのアプリケーション層のプロトコルを安全に利用するために,SSLを利用することは珍しくない。
以下にSMTP-SSLの利用例を示す。ここではopensslコマンドを使用する。opensslの機能はさまざまあり,引数としてコマンドを指定する。
以下の例では,s_clientを使用する。telnetやnc(netcat)がTCP(トランスポート層)での通信を提供するソフトウェアと考えるなら,opensslのs_clientコマンドはSSL(セッション層)での通信を提供するソフトウェアと考えれば良い。オプションの詳細については"man s_client"で閲覧できる。
user% openssl s_client -connect smtp.gmail.com:465 -crlf -ign_eof
CONNECTED(00000003)
depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA
verify error:num=20:unable to get local issuer certificate
verify return:0
---
Certificate chain
0 s:/C=US/ST=California/L=Mountain View/O=Google Inc/CN=smtp.gmail.com
i:/C=US/O=Google Inc/CN=Google Internet Authority G2
1 s:/C=US/O=Google Inc/CN=Google Internet Authority G2
i:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
2 s:/C=US/O=GeoTrust Inc./CN=GeoTrust Global CA
i:/C=US/O=Equifax/OU=Equifax Secure Certificate Authority
---
Server certificate
-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIIGcMF7jeVMoAwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
ー中略ー
Verify return code: 20 (unable to get local issuer certificate)
---
220 mx.google.com ESMTP n7sm9349346pdl.90 - gsmtp
EHLO localhost
250-mx.google.com at your service, [153.198.XXX.XXX]
250-SIZE 35882577
250-8BITMIME
250-AUTH LOGIN PLAIN XOAUTH XOAUTH2 PLAIN-CLIENTTOKEN OAUTHBEARER
250-ENHANCEDSTATUSCODES
250-PIPELINING
250-CHUNKING
250 SMTPUTF8
認証方法を入力する。
AUTH LOGIN
334 VXNlcm5hbWU6
AUTH LOGINで認証を行う場合,ユーザ名とパスワードをそれぞれbase64でエンコードしたものを使用する。ここでXXXXXXXXXXはユーザ名をエンコードしたもの,YYYYYYYYYYはパスワードをエンコードしたものである。
XXXXXXXXXX
334 UGFzc3dvcmQ6
YYYYYYYYYY
235 2.7.0 Accepted
エンコードは,次のようにbase64コマンドやopensslのencコマンドで行うことができる。また,opensslのencコマンドのマニュアルはs_clientと同様"man enc"で閲覧できる。
パスワードのエンコードも同様である。XXXXXXXXXXやYYYYYYYYYYの部分にはこの結果を貼り付ければ良い。
これ以降は通常のSMTPと同じように行えば良いが,ここではあえてHTMLメールを送信する例を紹介する。
MAIL From: <me@gmail.com>
250 2.1.0 OK n7sm9349346pdl.90 - gsmtp
RCPT To: <you@gmail.com>
250 2.1.5 OK n7sm9349346pdl.90 - gsmtp
DATA
354 Go ahead n7sm9349346pdl.90 - gsmtp
Subject: html-mail
Mime-Version: 1.0;
Content-Type: text/html; charset="ISO-8859-1";
Content-Transfer-Encoding: 7bit;
<!DOCTYPE HTML>
<html lang="ja-JP">
<body>
<h1>こんにちわ</h1>
</body>
<html>
.
250 2.0.0 OK 1413388691 n7sm9349346pdl.90 - gsmtp
QUIT
221 2.0.0 closing connection n7sm9349346pdl.90 - gsmtp
read:errno=0