[rtmpdump] r122 - in trunk: Makefile rtmpdump.c streams.c swfvfy.c
hyc
subversion at mplayerhq.hu
Tue Dec 29 00:08:07 CET 2009
Author: hyc
Date: Tue Dec 29 00:08:06 2009
New Revision: 122
Log:
Automate SWF verification, use -W instead of -s
Added:
trunk/swfvfy.c
Modified:
trunk/Makefile
trunk/rtmpdump.c
trunk/streams.c
Modified: trunk/Makefile
==============================================================================
--- trunk/Makefile Mon Dec 28 09:59:15 2009 (r121)
+++ trunk/Makefile Tue Dec 29 00:08:06 2009 (r122)
@@ -4,7 +4,7 @@ LD=$(CROSS_COMPILE)ld
OPT=-O2
CFLAGS=-Wall $(XCFLAGS) $(INC) $(OPT)
LDFLAGS=-Wall $(XLDFLAGS)
-LIBS=-lcrypto
+LIBS=-lcrypto -lcurl -lz
THREADLIB=-lpthread
SLIBS=$(THREADLIB) $(LIBS)
@@ -26,7 +26,7 @@ osx:
@$(MAKE) XCFLAGS="-arch ppc -arch i386" $(MAKEFLAGS) progs
mingw:
- @$(MAKE) CROSS_COMPILE=mingw32- LIBS="-lws2_32 -lwinmm -lcrypto -lgdi32" THREADLIB= EXT=.exe $(MAKEFLAGS) progs
+ @$(MAKE) CROSS_COMPILE=mingw32- LIBS="-lws2_32 -lwinmm -lgdi32 $(LIBS)" THREADLIB= EXT=.exe $(MAKEFLAGS) progs
cygwin:
@$(MAKE) XCFLAGS=-static XLDFLAGS="-static-libgcc -static" EXT=.exe $(MAKEFLAGS) progs
@@ -37,10 +37,10 @@ arm:
clean:
rm -f *.o rtmpdump$(EXT) streams$(EXT)
-streams: log.o rtmp.o amf.o streams.o parseurl.o
+streams: log.o rtmp.o amf.o streams.o parseurl.o swfvfy.o
$(CC) $(LDFLAGS) $^ -o $@$(EXT) $(SLIBS)
-rtmpdump: log.o rtmp.o amf.o rtmpdump.o parseurl.o
+rtmpdump: log.o rtmp.o amf.o rtmpdump.o parseurl.o swfvfy.o
$(CC) $(LDFLAGS) $^ -o $@$(EXT) $(LIBS)
rtmpsrv: log.o rtmp.o amf.o rtmpsrv.o
@@ -48,8 +48,9 @@ rtmpsrv: log.o rtmp.o amf.o rtmpsrv.o
log.o: log.c log.h Makefile
parseurl.o: parseurl.c parseurl.h log.h Makefile
-streams.o: streams.c rtmp.h log.h Makefile
+streams.o: streams.c rtmp.h log.h swfvfy.o Makefile
rtmp.o: rtmp.c rtmp.h handshake.h dh.h log.h amf.h Makefile
amf.o: amf.c amf.h bytes.h log.h Makefile
rtmpdump.o: rtmpdump.c rtmp.h log.h amf.h Makefile
rtmpsrv.o: rtmpsrv.c rtmp.h log.h amf.h Makefile
+swfvfy.o: swfvfy.c
Modified: trunk/rtmpdump.c
==============================================================================
--- trunk/rtmpdump.c Mon Dec 28 09:59:15 2009 (r121)
+++ trunk/rtmpdump.c Tue Dec 29 00:08:06 2009 (r122)
@@ -45,6 +45,17 @@
#include "log.h"
#include "parseurl.h"
+#ifdef CRYPTO
+#include <curl/curl.h>
+#define HASHLEN 32
+extern int SWFVerify(const char *url, unsigned int *size, unsigned char *hash);
+#define InitCurl() curl_global_init(CURL_GLOBAL_ALL)
+#define FreeCurl() curl_global_cleanup()
+#else
+#define InitCurl()
+#define FreeCurl()
+#endif
+
#define RTMPDUMP_VERSION "v2.0"
#define RD_SUCCESS 0
@@ -1099,6 +1110,10 @@ main(int argc, char **argv)
AVal token = { 0, 0 };
char *sockshost = 0;
+#ifdef CRYPTO
+ unsigned char hash[HASHLEN];
+#endif
+
char *flvFile = 0;
#undef OSS
@@ -1118,8 +1133,6 @@ main(int argc, char **argv)
signal(SIGQUIT, sigIntHandler);
#endif
- /* sleep(30); */
-
// Check for --quiet option before printing any output
int index = 0;
while (index < argc)
@@ -1134,6 +1147,17 @@ main(int argc, char **argv)
LogPrintf
("(c) 2009 Andrej Stepanchuk, Howard Chu, The Flvstreamer Team; license: GPL\n");
+ if (!InitSockets())
+ {
+ Log(LOGERROR,
+ "Couldn't load sockets support on your platform, exiting!");
+ return RD_FAILED;
+ }
+
+ InitCurl();
+
+ /* sleep(30); */
+
int opt;
struct option longopts[] = {
{"help", 0, NULL, 'h'},
@@ -1151,6 +1175,7 @@ main(int argc, char **argv)
#ifdef CRYPTO
{"swfhash", 1, NULL, 'w'},
{"swfsize", 1, NULL, 'x'},
+ {"swfVfy", 1, NULL, 'W'},
#endif
{"flashVer", 1, NULL, 'f'},
{"live", 0, NULL, 'v'},
@@ -1172,7 +1197,7 @@ main(int argc, char **argv)
while ((opt =
getopt_long(argc, argv,
- "hVveqzr:s:t:p:a:b:f:o:u:n:c:l:y:m:k:d:A:B:T:w:x:S:#",
+ "hVveqzr:s:t:p:a:b:f:o:u:n:c:l:y:m:k:d:A:B:T:w:x:W:S:#",
longopts, NULL)) != -1)
{
switch (opt)
@@ -1203,6 +1228,8 @@ main(int argc, char **argv)
("--swfhash|-w hexstring SHA256 hash of the decompressed SWF file (32 bytes)\n");
LogPrintf
("--swfsize|-x num Size of the decompressed SWF file, required for SWFVerification\n");
+ LogPrintf
+ ("--swfVfy|-W url URL to player swf file, compute hash/size automatically\n");
#endif
LogPrintf
("--auth|-u string Authentication string to be appended to the connect string\n");
@@ -1246,13 +1273,13 @@ main(int argc, char **argv)
case 'w':
{
int res = hex2bin(optarg, &swfHash.av_val);
- if (res != 32)
+ if (res != HASHLEN)
{
swfHash.av_val = NULL;
Log(LOGWARNING,
- "Couldn't parse swf hash hex string, not heyxstring or not 32 bytes, ignoring!");
+ "Couldn't parse swf hash hex string, not heyxstring or not %d bytes, ignoring!", HASHLEN);
}
- swfHash.av_len = 32;
+ swfHash.av_len = HASHLEN;
break;
}
case 'x':
@@ -1268,6 +1295,13 @@ main(int argc, char **argv)
}
break;
}
+ case 'W':
+ if (SWFVerify(optarg, &swfSize, hash) == 0)
+ {
+ swfHash.av_val = (char *)hash;
+ swfHash.av_len = HASHLEN;
+ }
+ break;
#endif
case 'k':
nSkipKeyFrames = atoi(optarg);
@@ -1488,12 +1522,6 @@ main(int argc, char **argv)
STR2AVAL(flashVer, DEFAULT_FLASH_VER);
}
- if (!InitSockets())
- {
- Log(LOGERROR,
- "Couldn't load sockets support on your platform, exiting!");
- return RD_FAILED;
- }
if (tcUrl.av_len == 0 && app.av_len != 0)
{
@@ -1689,6 +1717,8 @@ clean:
if (file != 0)
fclose(file);
+ FreeCurl();
+
CleanupSockets();
#ifdef _DEBUG
Modified: trunk/streams.c
==============================================================================
--- trunk/streams.c Mon Dec 28 09:59:15 2009 (r121)
+++ trunk/streams.c Tue Dec 29 00:08:06 2009 (r122)
@@ -37,6 +37,17 @@
#include <pthread.h>
#endif
+#ifdef CRYPTO
+#include <curl/curl.h>
+#define HASHLEN 32
+extern int SWFVerify(const char *url, unsigned int *size, unsigned char *hash);
+#define InitCurl() curl_global_init(CURL_GLOBAL_ALL)
+#define FreeCurl() curl_global_cleanup()
+#else
+#define InitCurl()
+#define FreeCurl()
+#endif
+
#define RTMPDUMP_STREAMS_VERSION "v2.0"
#define RD_SUCCESS 0
@@ -915,13 +926,13 @@ ParseOption(char opt, char *arg, RTMP_RE
case 'w':
{
int res = hex2bin(arg, &req->swfHash.av_val);
- if (!res || res != 32)
+ if (!res || res != HASHLEN)
{
req->swfHash.av_val = NULL;
Log(LOGWARNING,
- "Couldn't parse swf hash hex string, not heyxstring or not 32 bytes, ignoring!");
+ "Couldn't parse swf hash hex string, not hexstring or not %d bytes, ignoring!", HASHLEN);
}
- req->swfHash.av_len = 32;
+ req->swfHash.av_len = HASHLEN;
break;
}
case 'x':
@@ -937,6 +948,17 @@ ParseOption(char opt, char *arg, RTMP_RE
}
break;
}
+ case 'W':
+ {
+ unsigned char hash[HASHLEN];
+ if (SWFVerify(arg, &req->swfSize, hash) == 0)
+ {
+ req->swfHash.av_val = malloc(HASHLEN);
+ req->swfHash.av_len = HASHLEN;
+ memcpy(req->swfHash.av_val, hash, HASHLEN);
+ }
+ }
+ break;
case 'b':
{
int32_t bt = atol(arg);
@@ -1102,8 +1124,11 @@ main(int argc, char **argv)
{"tcUrl", 1, NULL, 't'},
{"pageUrl", 1, NULL, 'p'},
{"app", 1, NULL, 'a'},
+#ifdef CRYPTO
{"swfhash", 1, NULL, 'w'},
{"swfsize", 1, NULL, 'x'},
+ {"swfVfy", 1, NULL, 'W'},
+#endif
{"auth", 1, NULL, 'u'},
{"flashVer", 1, NULL, 'f'},
{"live", 0, NULL, 'v'},
@@ -1127,9 +1152,13 @@ main(int argc, char **argv)
signal(SIGINT, sigIntHandler);
signal(SIGPIPE, SIG_IGN);
+ InitSockets();
+
+ InitCurl();
+
while ((opt =
getopt_long(argc, argv,
- "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:", longopts,
+ "hvqVzr:s:t:p:a:f:u:n:c:l:y:m:d:D:A:B:T:g:w:x:W:", longopts,
NULL)) != -1)
{
switch (opt)
@@ -1153,11 +1182,15 @@ main(int argc, char **argv)
("--tcUrl|-t url URL to played stream (default: \"rtmp://host[:port]/app\")\n");
LogPrintf("--pageUrl|-p url Web URL of played programme\n");
LogPrintf("--app|-a app Name of player used\n");
+#ifdef CRYPTO
LogPrintf
("--swfhash|-w hexstring SHA256 hash of the decompressed SWF file (32 bytes)\n");
LogPrintf
("--swfsize|-x num Size of the decompressed SWF file, required for SWFVerification\n");
LogPrintf
+ ("--swfVfy|-W url URL to player swf file, compute hash/size automatically\n");
+#endif
+ LogPrintf
("--auth|-u string Authentication string to be appended to the connect string\n");
LogPrintf
("--flashVer|-f string Flash version string (default: \"%s\")\n",
@@ -1234,8 +1267,6 @@ main(int argc, char **argv)
netstackdump_read = fopen("netstackdump_read", "wb");
#endif
- InitSockets();
-
// start text UI
ThreadCreate(controlServerThread, 0);
@@ -1255,6 +1286,8 @@ main(int argc, char **argv)
}
Log(LOGDEBUG, "Done, exiting...");
+ FreeCurl();
+
CleanupSockets();
#ifdef _DEBUG
Added: trunk/swfvfy.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ trunk/swfvfy.c Tue Dec 29 00:08:06 2009 (r122)
@@ -0,0 +1,226 @@
+/*
+ * Copyright (C) 2009 Howard Chu
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with RTMPDump; see the file COPYING. If not, write to
+ * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <openssl/sha.h>
+#include <openssl/hmac.h>
+#include <curl/curl.h>
+#include <zlib.h>
+
+struct info {
+ HMAC_CTX *ctx;
+ z_stream *zs;
+ char *date;
+ int first;
+ int zlib;
+ int size;
+};
+
+#define CHUNK 16384
+
+static size_t
+swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ struct info *i = stream;
+ char *p = ptr;
+ size_t len = size * nmemb;
+
+ if (i->first)
+ {
+ i->first = 0;
+ /* compressed? */
+ if (!strncmp(p, "CWS", 3))
+ {
+ *p = 'F';
+ i->zlib = 1;
+ }
+ HMAC_Update(i->ctx, (unsigned char *)p, 8);
+ p += 8;
+ len -= 8;
+ i->size = 8;
+ }
+
+ if (i->zlib)
+ {
+ unsigned char out[CHUNK];
+ i->zs->next_in = (unsigned char *)p;
+ i->zs->avail_in = len;
+ do
+ {
+ i->zs->avail_out = CHUNK;
+ i->zs->next_out = out;
+ inflate(i->zs, Z_NO_FLUSH);
+ len = CHUNK - i->zs->avail_out;
+ i->size += len;
+ HMAC_Update(i->ctx, out, len);
+ } while (i->zs->avail_out == 0);
+ }
+ else
+ {
+ i->size += len;
+ HMAC_Update(i->ctx, (unsigned char *)p, len);
+ }
+ return size * nmemb;
+}
+
+static size_t
+hdrcrunch(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+ struct info *i = stream;
+ char *p = ptr;
+ size_t len = size * nmemb;
+
+ if (!strncmp(p, "Last-Modified: ", 15))
+ {
+ int l = len-15;
+ strncpy(i->date, p+15, l);
+ if (i->date[l-1] == '\n')
+ l--;
+ if (i->date[l-1] == '\r')
+ l--;
+ i->date[l] = '\0';
+ }
+ return len;
+}
+
+#define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
+
+int
+SWFVerify(const char *url, unsigned int *size, unsigned char *hash)
+{
+ FILE *f = NULL;
+ char *path, *home, date[64];
+ long pos = 0;
+ int i, got = 0, ret = 0;
+ unsigned int hlen;
+ CURL *c;
+ char csbuf[96];
+ struct curl_slist cs = {csbuf};
+ struct info in;
+ z_stream zs = {0};
+ HMAC_CTX ctx;
+
+ date[0] = '\0';
+ home = getenv("HOME");
+ if (!home)
+ home = ".";
+
+ path=malloc(strlen(home)+sizeof("/.swfinfo"));
+ strcpy(path, home);
+ strcat(path, "/.swfinfo");
+
+ f = fopen(path, "r+");
+ if (f)
+ {
+ char buf[4096], *file;
+
+ file = strrchr(url, '/');
+
+ while (fgets(buf, sizeof(buf), f))
+ {
+ char *r1;
+
+ got = 0;
+
+ if (strncmp(buf, "url: ", 5))
+ continue;
+ r1 = strrchr(buf, '/');
+ buf[strlen(buf)-1] = '\0';
+ if (strcmp(r1, file))
+ continue;
+ pos = ftell(f);
+ while (got < 3 && fgets(buf, sizeof(buf), f))
+ {
+ if (!strncmp(buf, "size: ", 6))
+ {
+ *size = strtol(buf+6, NULL, 16);
+ got++;
+ }
+ else if (!strncmp(buf, "hash: ", 6))
+ {
+ unsigned char *ptr = hash, *in = (unsigned char *)buf+6;
+ int l = strlen((char *)in)-1;
+ for (i=0; i<l; i+=2)
+ *ptr++ = (HEX2BIN(in[i]) << 4) | HEX2BIN(in[i+1]);
+ got++;
+ }
+ else if (!strncmp(buf, "date: ", 6))
+ {
+ buf[strlen(buf)-1] = '\0';
+ strncpy(date, buf, sizeof(date));
+ got++;
+ }
+ else if (!strncmp(buf, "url: ", 5))
+ break;
+ }
+ break;
+ }
+ }
+
+ in.first = 1;
+ in.date = date;
+ HMAC_CTX_init(&ctx);
+ HMAC_Init_ex(&ctx, "Genuine Adobe Flash Player 001", 30, EVP_sha256(), NULL);
+ inflateInit(&zs);
+ in.ctx = &ctx;
+ in.zs = &zs;
+
+ c = curl_easy_init();
+ curl_easy_setopt(c, CURLOPT_WRITEFUNCTION, swfcrunch);
+ curl_easy_setopt(c, CURLOPT_WRITEDATA, &in);
+ curl_easy_setopt(c, CURLOPT_HEADERFUNCTION, hdrcrunch);
+ curl_easy_setopt(c, CURLOPT_HEADERDATA, &in);
+ curl_easy_setopt(c, CURLOPT_URL, url);
+ if (date[0])
+ {
+ sprintf(csbuf, "If-Modified-Since: %s", date);
+ curl_easy_setopt(c, CURLOPT_HTTPHEADER, &cs);
+ }
+ ret = curl_easy_perform(c);
+ curl_easy_cleanup(c);
+
+ inflateEnd(&zs);
+
+ if (!ret && !in.first)
+ {
+ HMAC_Final(&ctx, (unsigned char *)hash, &hlen);
+ if (got && pos)
+ fseek(f, pos, SEEK_SET);
+ else
+ {
+ if (!f)
+ f = fopen(path, "w");
+ fseek(f, 0, SEEK_END);
+ fprintf(f, "url: %s\n", url);
+ }
+ fprintf(f, "date: %s\n", date);
+ fprintf(f, "size: %08x\n", in.size);
+ fprintf(f, "hash: ");
+ for (i=0; i<SHA256_DIGEST_LENGTH; i++)
+ fprintf(f, "%02x", hash[i]);
+ fprintf(f, "\n");
+ *size = in.size;
+ }
+ HMAC_CTX_cleanup(&ctx);
+ fclose(f);
+ return ret;
+}
More information about the rtmpdump
mailing list