From 8256c0a3416e619f186875b3162c52a7d302132c Mon Sep 17 00:00:00 2001 From: Philip Gladstone Date: Sat, 27 Jul 2002 03:03:04 +0000 Subject: [PATCH] * Make asf streaming work again. Now uses the output format asf_stream. * Add ip address based acls for streams. I recommend adding ACL entries for all feeds to control who can submit stuff. You might also want to consider who can get to your status page. * Make logging work again if customlog == "-" Originally committed as revision 821 to svn://svn.ffmpeg.org/ffmpeg/trunk --- ffserver.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 116 insertions(+), 14 deletions(-) diff --git a/ffserver.c b/ffserver.c index c7b2bc5907..c9bd4b92f0 100644 --- a/ffserver.c +++ b/ffserver.c @@ -154,6 +154,18 @@ enum StreamType { STREAM_TYPE_REDIRECT, }; +enum IPAddressAction { + IP_ALLOW = 1, + IP_DENY, +}; + +typedef struct IPAddressACL { + struct IPAddressACL *next; + enum IPAddressAction action; + struct in_addr first; + struct in_addr last; +} IPAddressACL; + /* description of each stream of the ffserver.conf file */ typedef struct FFStream { enum StreamType stream_type; @@ -161,6 +173,7 @@ typedef struct FFStream { struct FFStream *feed; /* feed we are using (can be null if coming from file) */ AVOutputFormat *fmt; + IPAddressACL *acl; int nb_streams; int prebuffer; /* Number of millseconds early to start */ long max_time; /* Number of milliseconds to run */ @@ -957,6 +970,23 @@ static void get_word(char *buf, int buf_size, const char **pp) *pp = p; } +static int validate_acl(FFStream *stream, HTTPContext *c) +{ + enum IPAddressAction last_action = IP_DENY; + IPAddressACL *acl; + struct in_addr *src = &c->from_addr.sin_addr; + + for (acl = stream->acl; acl; acl = acl->next) { + if (src->s_addr >= acl->first.s_addr && src->s_addr <= acl->last.s_addr) { + return (acl->action == IP_ALLOW) ? 1 : 0; + } + last_action = acl->action; + } + + /* Nothing matched, so return not the last action */ + return (last_action == IP_DENY) ? 1 : 0; +} + /* parse http request and prepare header */ static int http_parse_request(HTTPContext *c) { @@ -1077,7 +1107,7 @@ static int http_parse_request(HTTPContext *c) stream = first_stream; while (stream != NULL) { - if (!strcmp(stream->filename, filename)) + if (!strcmp(stream->filename, filename) && validate_acl(stream, c)) break; stream = stream->next; } @@ -1342,14 +1372,10 @@ static int http_parse_request(HTTPContext *c) q += sprintf(q, "Pragma: no-cache\r\n"); /* for asf, we need extra headers */ - if (!strcmp(c->stream->fmt->name,"asf")) { + if (!strcmp(c->stream->fmt->name,"asf_stream")) { /* Need to allocate a client id */ - static int wmp_session; - if (!wmp_session) - wmp_session = time(0) & 0xffffff; - - c->wmp_client_id = ++wmp_session; + c->wmp_client_id = random() & 0x7fffffff; q += sprintf(q, "Server: Cougar 4.1.0.3923\r\nCache-Control: no-cache\r\nPragma: client-id=%d\r\nPragma: features=\"broadcast\"\r\n", c->wmp_client_id); mime_type = "application/octet-stream"; @@ -1719,6 +1745,12 @@ static int open_input_stream(HTTPContext *c, const char *info) if (input_filename[0] == '\0') return -1; +#if 0 + { time_t when = stream_pos / 1000000; + http_log("Stream pos = %lld, time=%s", stream_pos, ctime(&when)); + } +#endif + /* open stream */ if (av_open_input_file(&s, input_filename, NULL, buf_size, NULL) < 0) { http_log("%s not found", input_filename); @@ -3447,7 +3479,7 @@ int parse_ffconfig(const char *filename) q = strrchr(stream->filename, '>'); if (*q) *q = '\0'; - stream->fmt = guess_format(NULL, stream->filename, NULL); + stream->fmt = guess_stream_format(NULL, stream->filename, NULL); memset(&audio_enc, 0, sizeof(AVCodecContext)); memset(&video_enc, 0, sizeof(AVCodecContext)); audio_id = CODEC_ID_NONE; @@ -3485,7 +3517,7 @@ int parse_ffconfig(const char *filename) /* jpeg cannot be used here, so use single frame jpeg */ if (!strcmp(arg, "jpeg")) strcpy(arg, "singlejpeg"); - stream->fmt = guess_format(arg, NULL, NULL); + stream->fmt = guess_stream_format(arg, NULL, NULL); if (!stream->fmt) { fprintf(stderr, "%s:%d: Unknown Format: %s\n", filename, line_num, arg); @@ -3523,7 +3555,7 @@ int parse_ffconfig(const char *filename) } else if (!strcasecmp(cmd, "Preroll")) { get_arg(arg, sizeof(arg), &p); if (stream) { - stream->prebuffer = atoi(arg) * 1000; + stream->prebuffer = atof(arg) * 1000; } } else if (!strcasecmp(cmd, "StartSendOnKey")) { if (stream) { @@ -3548,7 +3580,7 @@ int parse_ffconfig(const char *filename) } else if (!strcasecmp(cmd, "MaxTime")) { get_arg(arg, sizeof(arg), &p); if (stream) { - stream->max_time = atoi(arg) * 1000; + stream->max_time = atof(arg) * 1000; } } else if (!strcasecmp(cmd, "AudioBitRate")) { get_arg(arg, sizeof(arg), &p); @@ -3630,6 +3662,72 @@ int parse_ffconfig(const char *filename) video_id = CODEC_ID_NONE; } else if (!strcasecmp(cmd, "NoAudio")) { audio_id = CODEC_ID_NONE; + } else if (!strcasecmp(cmd, "ACL")) { + IPAddressACL acl; + struct hostent *he; + + get_arg(arg, sizeof(arg), &p); + if (strcasecmp(arg, "allow") == 0) { + acl.action = IP_ALLOW; + } else if (strcasecmp(arg, "deny") == 0) { + acl.action = IP_DENY; + } else { + fprintf(stderr, "%s:%d: ACL action '%s' is not ALLOW or DENY\n", + filename, line_num, arg); + errors++; + } + + get_arg(arg, sizeof(arg), &p); + + he = gethostbyname(arg); + if (!he) { + fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n", + filename, line_num, arg); + errors++; + } else { + /* Only take the first */ + acl.first = *(struct in_addr *) he->h_addr_list[0]; + acl.last = acl.first; + } + + get_arg(arg, sizeof(arg), &p); + + if (arg[0]) { + he = gethostbyname(arg); + if (!he) { + fprintf(stderr, "%s:%d: ACL refers to invalid host or ip address '%s'\n", + filename, line_num, arg); + errors++; + } else { + /* Only take the first */ + acl.last = *(struct in_addr *) he->h_addr_list[0]; + } + } + + if (!errors) { + IPAddressACL *nacl = (IPAddressACL *) av_mallocz(sizeof(*nacl)); + IPAddressACL **naclp = 0; + + *nacl = acl; + nacl->next = 0; + + if (stream) { + naclp = &stream->acl; + } else if (feed) { + naclp = &feed->acl; + } else { + fprintf(stderr, "%s:%d: ACL found not in or \n", + filename, line_num); + errors++; + } + + if (naclp) { + while (*naclp) + naclp = &(*naclp)->next; + + *naclp = nacl; + } + } } else if (!strcasecmp(cmd, "RTSPOption")) { get_arg(arg, sizeof(arg), &p); if (stream) { @@ -3830,6 +3928,8 @@ int main(int argc, char **argv) putenv("http_proxy"); /* Kill the http_proxy */ + srandom(gettime_ms() + (getpid() << 16)); + /* address on which the server will handle HTTP connections */ my_http_addr.sin_family = AF_INET; my_http_addr.sin_port = htons (8080); @@ -3875,10 +3975,12 @@ int main(int argc, char **argv) setsid(); chdir("/"); close(0); - close(1); - close(2); open("/dev/null", O_RDWR); - dup(0); + if (!strcmp(logfilename, "-")) { + close(1); + dup(0); + } + close(2); dup(0); } }