int protocol,
const char *hostname,
unsigned int port,
+ const char *sockshost,
const char *playpath,
const char *tcUrl,
const char *swfUrl,
Link.SWFSize = 0;
}
+ if(sockshost)
+ {
+ const char *socksport = strchr(sockshost, ':');
+
+ Link.sockshost = strndup(sockshost,
+ socksport ? socksport - sockshost : strlen(sockshost));
+ Link.socksport = socksport ? atoi(socksport + 1) : 1080;
+ Log(LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", Link.sockshost, Link.socksport);
+ } else {
+ Link.sockshost = NULL;
+ Link.socksport = 0;
+ }
+
+
Link.tcUrl = tcUrl;
Link.swfUrl = swfUrl;
Link.pageUrl = pageUrl;
Link.port = 1935;
}
+static bool add_addr_info(sockaddr_in* service, const char *hostname, int port)
+{
+ service->sin_addr.s_addr = inet_addr(hostname);
+ if (service->sin_addr.s_addr == INADDR_NONE)
+ {
+ struct hostent *host = gethostbyname(hostname);
+ if (host == NULL || host->h_addr == NULL)
+ {
+ Log(LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
+ return false;
+ }
+ service->sin_addr = *(struct in_addr*)host->h_addr;
+ }
+
+ service->sin_port = htons(port);
+ return true;
+}
+
bool CRTMP::Connect() {
if (!Link.hostname)
return false;
sockaddr_in service;
memset(&service, 0, sizeof(sockaddr_in));
service.sin_family = AF_INET;
- service.sin_addr.s_addr = inet_addr(Link.hostname);
- if (service.sin_addr.s_addr == INADDR_NONE)
+
+ if (Link.socksport)
{
- struct hostent *host = gethostbyname(Link.hostname);
- if (host == NULL || host->h_addr == NULL)
- {
- Log(LOGERROR, "Problem accessing the DNS. (addr: %s)", Link.hostname);
- return false;
- }
- service.sin_addr = *(struct in_addr*)host->h_addr;
+ // Connect via SOCKS
+ if(!add_addr_info(&service, Link.sockshost, Link.socksport)) return false;
+ } else {
+ // Connect directly
+ if(!add_addr_info(&service, Link.hostname, Link.port)) return false;
}
- service.sin_port = htons(Link.port);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket != -1)
{
return false;
}
+ if(Link.socksport) {
+ Log(LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
+ if (!SocksNegotiate())
+ {
+ Log(LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
+ Close();
+ return false;
+ }
+ }
+
Log(LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
if (!HandShake())
{
return true;
}
+bool CRTMP::SocksNegotiate() {
+ char packet[255];
+ sockaddr_in service;
+ memset(&service, 0, sizeof(sockaddr_in));
+
+ add_addr_info(&service, Link.hostname, Link.port);
+ unsigned long addr = htonl(service.sin_addr.s_addr);
+
+ int len = snprintf(packet, sizeof packet, "%c%c%c%c%c%c%c%c%c",
+ 4, 1, // SOCKS 4, connect
+ (Link.port >> 8) & 0xFF,
+ (Link.port) & 0xFF,
+ (char) (addr >> 24) & 0xFF, (char) (addr >> 16) & 0xFF,
+ (char) (addr >> 8) & 0xFF, (char) addr & 0xFF,
+ 0); // NULL terminate
+
+ WriteN(packet, len);
+
+ if(ReadN(packet, 8) != 8)
+ return false;
+
+ if(packet[0] == 0 && packet[1] == 90) {
+ return true;
+ } else {
+ Log(LOGERROR, "%s, SOCKS returned error code %d", packet[1]);
+ return false;
+ }
+}
+
bool CRTMP::ConnectStream(double seekTime) {
if (seekTime >= -2.0)
Link.seekTime = seekTime;
char *swfHash = 0;
uint32_t swfSize = 0;
char *flashVer = 0;
+ char *sockshost = 0;
char *flvFile = 0;
{"help", 0, NULL, 'h'},
{"host", 1, NULL, 'n'},
{"port", 1, NULL, 'c'},
+ {"socks", 1, NULL, 'S'},
{"protocol",1, NULL, 'l'},
{"playpath",1, NULL, 'y'},
{"rtmp", 1, NULL, 'r'},
{0,0,0,0}
};
- while((opt = getopt_long(argc, argv, "hVveqzr:s:t:p:a:f:o:u:n:c:l:y:m:k:d:A:B:w:x:", longopts, NULL)) != -1) {
+ while((opt = getopt_long(argc, argv, "hVveqzr:s:t:p:a:f:o:u:n:c:l:y:m:k:d:A:B:w:x:S:", longopts, NULL)) != -1) {
switch(opt) {
case 'h':
LogPrintf("\nThis program dumps the media content streamed over rtmp.\n\n");
LogPrintf("--rtmp|-r url URL (e.g. rtmp//hotname[:port]/path)\n");
LogPrintf("--host|-n hostname Overrides the hostname in the rtmp url\n");
LogPrintf("--port|-c port Overrides the port in the rtmp url\n");
+ LogPrintf("--socks|-S host:port Use the specified SOCKS proxy\n");
LogPrintf("--protocol|-l Overrides the protocol in the rtmp url (0 - RTMP, 3 - RTMPE)\n");
LogPrintf("--playpath|-y Overrides the playpath parsed from rtmp url\n");
LogPrintf("--swfUrl|-s url URL to player swf file\n");
case 'z':
debuglevel = LOGALL;
break;
+ case 'S':
+ sockshost = optarg;
+ break;
default:
LogPrintf("unknown option: %c\n", opt);
break;
memset(buffer, 0, bufferSize);
CRTMP *rtmp = new CRTMP();
- rtmp->SetupStream(protocol, hostname, port, playpath, tcUrl, swfUrl,
+ rtmp->SetupStream(protocol, hostname, port, sockshost, playpath, tcUrl, swfUrl,
pageUrl, app, auth, swfHash, swfSize, flashVer, subscribepath,
dSeek, bLiveStream, timeout);