diff --git a/.gitmodules b/.gitmodules old mode 100644 new mode 100755 index bb90ca9..f3bb541 --- a/.gitmodules +++ b/.gitmodules @@ -13,3 +13,4 @@ [submodule "src/ftpd/pure-ftpd"] path = src/ftpd/pure-ftpd url = https://github.com/jedisct1/pure-ftpd.git + diff --git a/src/busybox/.config b/src/busybox/.config index f1d07fb..0ff2083 100644 --- a/src/busybox/.config +++ b/src/busybox/.config @@ -849,7 +849,7 @@ CONFIG_FEATURE_HTTPD_CGI=y # CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set # CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set # CONFIG_FEATURE_HTTPD_PROXY is not set -# CONFIG_FEATURE_HTTPD_GZIP is not set +CONFIG_FEATURE_HTTPD_GZIP=y CONFIG_IFCONFIG=y CONFIG_FEATURE_IFCONFIG_STATUS=y CONFIG_FEATURE_IFCONFIG_SLIP=y diff --git a/src/busybox/httpd.patch b/src/busybox/httpd.patch new file mode 100644 index 0000000..7371ff5 --- /dev/null +++ b/src/busybox/httpd.patch @@ -0,0 +1,14 @@ +--- busybox/networking/httpd.c 2019-02-08 20:24:33.917338666 +0100 ++++ new/yi-hack-v4/src/busybox/busybox/networking/httpd.c 2019-02-06 16:33:46.582275044 +0100 +@@ -2430,9 +2430,9 @@ + tptr = urlcopy + 1; /* skip first '/' */ + + #if ENABLE_FEATURE_HTTPD_CGI +- if (is_prefixed_with(tptr, "cgi-bin/")) { ++ if (is_prefixed_with(tptr, "onvif/") || is_prefixed_with(tptr, "cgi-bin/")) { + if (tptr[8] == '\0') { +- /* protect listing "cgi-bin/" */ ++ /* protect listing "onvif/" and "cgi-bin/" */ + send_headers_and_exit(HTTP_FORBIDDEN); + } + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); diff --git a/src/busybox/init.busybox b/src/busybox/init.busybox index 5d8fe89..9c8a481 100755 --- a/src/busybox/init.busybox +++ b/src/busybox/init.busybox @@ -10,3 +10,6 @@ git reset --hard || exit 1 cp ../.config ./ || exit 1 +cd $SCRIPT_DIR +patch -p0 < httpd.patch + diff --git a/src/static/static/home/yi-hack-v4/etc/system.conf b/src/static/static/home/yi-hack-v4/etc/system.conf index 3e27575..cfedf19 100755 --- a/src/static/static/home/yi-hack-v4/etc/system.conf +++ b/src/static/static/home/yi-hack-v4/etc/system.conf @@ -4,3 +4,4 @@ DROPBEAR=yes FTPD=yes PROXYCHAINSNG=no CHECK_UPDATES=yes +WSD=yes diff --git a/src/static/static/home/yi-hack-v4/script/system.sh b/src/static/static/home/yi-hack-v4/script/system.sh index f438aed..a92dc74 100755 --- a/src/static/static/home/yi-hack-v4/script/system.sh +++ b/src/static/static/home/yi-hack-v4/script/system.sh @@ -40,6 +40,10 @@ if [[ $(get_config DROPBEAR) == "yes" ]] ; then dropbear -R fi +if [[ $(get_config WSD) == "yes" ]] ; then + wsdiscovery wlan0 $(cat /home/app/.camver) +fi + # First run on startup, then every hour via crond $YI_HACK_PREFIX/script/check_update.sh diff --git a/src/wsdiscovery/compile.wsdiscovery b/src/wsdiscovery/compile.wsdiscovery new file mode 100755 index 0000000..004c2a7 --- /dev/null +++ b/src/wsdiscovery/compile.wsdiscovery @@ -0,0 +1,18 @@ +#!/bin/sh + +SCRIPT_DIR=$(cd `dirname $0` && pwd) +cd $SCRIPT_DIR + +echo "Building the WebService Discovery server..." +cd wsdiscovery +make clean +make + +mkdir -p ../_install +cp wsdiscovery ../_install + +mkdir -p ../_install/www/onvif +echo "Copying the onvif folder..." +cp ./onvif/* ../_install/www/onvif + +echo "Compilation succeeded." \ No newline at end of file diff --git a/src/wsdiscovery/init.wsdiscovery b/src/wsdiscovery/init.wsdiscovery new file mode 100755 index 0000000..ee9e7aa --- /dev/null +++ b/src/wsdiscovery/init.wsdiscovery @@ -0,0 +1,6 @@ +#!/bin/sh + +SCRIPT_DIR=$(cd `dirname $0` && pwd) +cd $SCRIPT_DIR + +rm -rf ./_install \ No newline at end of file diff --git a/src/wsdiscovery/install.wsdiscovery b/src/wsdiscovery/install.wsdiscovery new file mode 100755 index 0000000..2160b05 --- /dev/null +++ b/src/wsdiscovery/install.wsdiscovery @@ -0,0 +1,7 @@ +#!/bin/bash + +SCRIPT_DIR=$(cd `dirname $0` && pwd) +cd $SCRIPT_DIR + +rsync -a ./_install/wsdiscovery ../../build/home/yi-hack-v4/bin/ +rsync -a ./_install/www/* ../../build/home/yi-hack-v4/www/ \ No newline at end of file diff --git a/src/wsdiscovery/wsdiscovery/.gitignore b/src/wsdiscovery/wsdiscovery/.gitignore new file mode 100644 index 0000000..7dc40d0 --- /dev/null +++ b/src/wsdiscovery/wsdiscovery/.gitignore @@ -0,0 +1 @@ +wsdiscovery diff --git a/src/wsdiscovery/wsdiscovery/Makefile b/src/wsdiscovery/wsdiscovery/Makefile new file mode 100755 index 0000000..65e9aaf --- /dev/null +++ b/src/wsdiscovery/wsdiscovery/Makefile @@ -0,0 +1,11 @@ +CC=arm-hisiv300-linux-gcc +STRIP=arm-hisiv300-linux-strip + +all: wsdiscovery + +wsdiscovery: wsdiscovery.c + $(CC) -Os -o wsdiscovery wsdiscovery.c + $(STRIP) wsdiscovery + +clean: + rm -f wsdiscovery \ No newline at end of file diff --git a/src/wsdiscovery/wsdiscovery/onvif/device_service b/src/wsdiscovery/wsdiscovery/onvif/device_service new file mode 100755 index 0000000..b7661cc --- /dev/null +++ b/src/wsdiscovery/wsdiscovery/onvif/device_service @@ -0,0 +1,259 @@ +#!/bin/sh +POST_STRING=$(cat) +printf "Content-type: application/soap+xml\r\n\r\n" + +case $POST_STRING in + *GetSystemDateAndTime*) + printf " + + NTP + true + + %s + + + + %i + %i + %i + + + %i + %i + %i + + + + " "(UTC)" $(date +"%H") $(date +"%M") $(date +"%S") $(date +"%Y") $(date +"%m") $(date +"%d") + ;; + + *GetDeviceInformation*) + printf " + %s + %s + %s + %s + %s + " "YI Technology" $(cat /home/app/.camver) $(cat /home/app/.appver) $(ifconfig | awk '/HWaddr/{print substr($5,1)}') $(grep -e Hardware /proc/cpuinfo | awk '{print $3}') + ;; + + *GetScopes*) + printf " + + Fixed + onvif://www.onvif.org/type/video_encoder + + + Fixed + onvif://www.onvif.org/type/Network_Video_Transmitter + + + Configurable + onvif://www.onvif.org/name/%s + + + Fixed + onvif://www.onvif.org/type/video_analytics + + + Fixed + onvif://www.onvif.org/hardware/%s + + + Configurable + onvif://www.onvif.org/location/ + + + Fixed + onvif://www.onvif.org/type/ptz + + " $(cat /home/app/.camver) $(grep -e Hardware /proc/cpuinfo | awk '{print $3}') + ;; + + *GetNetworkInterfaces*) + printf " + + true + + wlan0 + %s + 1500 + + + true + + + %s + 24 + + true + + + + " $(ifconfig | awk '/HWaddr/{print substr($5,1)}') $(ifconfig | awk '/inet addr/{print substr($2,6)}') + ;; + + *GetDNS*) + printf " + + true + + IPv4 + %s + + + " $(cat /etc/resolv.conf | awk '{print substr($2,1)}') + ;; + + *GetNTP*) + printf " + + true + + " + ;; + + *GetCapabilities*) + IPADDR=$(ifconfig | awk '/inet addr/{print substr($2,6)}') + printf " + + + http://%s/onvif/device_service + + false + false + false + false + + + true + true + true + false + false + false + + 1 + 0 + + + + 0 + 0 + + + false + false + false + false + false + false + false + false + + + + http://%s/onvif/event_service + false + false + false + + + http://%s/onvif/media_service + + false + true + true + + + + http://%s/onvif/ptz_service + + + " $IPADDR $IPADDR $IPADDR $IPADDR + ;; + + *GetHostname*) + printf " + + false + %s + + " $(hostname) + ;; + + *GetNetworkProtocols*) + printf " + + HTTP + true + 80 + + + RTSP + true + 554 + + + HTTPS + false + 443 + + " + ;; + + *GetNetworkDefaultGateway*) + printf " + + %s + + " $(route | awk '/default/{print substr($2,1)}') + ;; + + *SystemReboot*) + printf " + Rebooting now. + " + reboot + ;; + + *GetDiscoveryMode*) + printf " + Discoverable + " + ;; + + *GetUsers*) + printf "" + cat /etc/passwd | while read USER; do + case $(echo $USER | cut -d: -f3) in + 0) GROUP="Administrator" ;; + *) GROUP="User" ;; + esac + printf " + %s + %s + " $(echo $USER | cut -d: -f1) $GROUP + done + printf "" + ;; + + *) + printf " + + env:Receiver + + ter:ActionNotSupported + + + + ActionNotSupported + + + The device do NOT support this feature. + + " + ;; +esac + +printf "" diff --git a/src/wsdiscovery/wsdiscovery/onvif/media_service b/src/wsdiscovery/wsdiscovery/onvif/media_service new file mode 100755 index 0000000..3f9eeef --- /dev/null +++ b/src/wsdiscovery/wsdiscovery/onvif/media_service @@ -0,0 +1,257 @@ +#!/bin/sh +POST_STRING=$(cat) + +case $(cat /home/app/.camver) in + *1080*) + MAINWIDTH=1920 + MAINHEIGHT=1080 + ;; + *) + MAINWIDTH=1280 + MAINHEIGHT=720 + ;; +esac + +printf "Content-type: application/soap+xml\r\n\r\n" + +case $POST_STRING in + *GetProfiles*) + printf " + + MainStream + + VideoSourceConfig + 2 + VideoSource_1 + + + + VideoEncoder_0 + 1 + H264 + + %i + %i + + 5 + + 20 + 20 + 3072 + + + 20 + Main + + + + IPv4 + 0.0.0.0 + + 0 + 3 + false + + PT0S + + + + SubStream + + VideoSourceConfig + 2 + VideoSource_1 + + + + VideoEncoder_1 + 1 + H264 + + 640 + 360 + + 5 + + 20 + 20 + 512 + + + 20 + Main + + + + IPv4 + 239.255.0.0 + + 1024 + 1 + false + + PT5S + + + " $MAINWIDTH $MAINHEIGHT $MAINWIDTH $MAINHEIGHT + ;; + + *GetVideoSources*) + printf " + + 20 + + %i + %i + + + " $MAINWIDTH $MAINHEIGHT + ;; + + *GetProfile*) + case $POST_STRING in + *profile_0*) + PROFILE=0 + WIDTH=$MAINWIDTH + HEIGHT=$MAINHEIGHT + ;; + *profile_1*) + PROFILE=1 + WIDTH=640 + HEIGHT=360 + ;; + esac + printf " + + MainStream + + VideoSourceConfig + 2 + VideoSource_1 + + + + VideoEncoder_%i + 1 + H264 + + %i + %i + + 5 + + 25 + 25 + 3072 + + + 25 + Main + + + + IPv4 + 239.255.0.0 + + 1024 + 1 + false + + PT5S + + + " $PROFILE $WIDTH $HEIGHT $PROFILE $PROFILE $WIDTH $HEIGHT + ;; + + *GetStreamUri*) + case $POST_STRING in + *profile_0*) + RTSPPATH="ch0_0.h264" + ;; + *profile_1*) + RTSPPATH="ch0_1.h264" + ;; + esac + printf " + + rtsp://%s/%s + true + true + PT5S + + " $(ifconfig | awk '/inet addr/{print substr($2,6)}') $RTSPPATH + ;; + + *GetSnapshotUri*) + + ;; + + *GetVideoEncoderConfigurationOptions*) + printf " + + + 1 + 6 + + + + 640 + 360 + + + %i + %i + + + 1 + 100 + + + 1 + 30 + + + 1 + 25 + + Main + Baseline + Extended + High + + + " $MAINWIDTH $MAINHEIGHT + ;; + + *GetVideoSourceConfiguration*) + printf " + + VideoSourceConfig + 2 + VideoSource_1 + + + " $MAINWIDTH $MAINHEIGHT + ;; + + *) + printf " + + env:Receiver + + ter:ActionNotSupported + + + + ActionNotSupported + + + The device do NOT support this feature. + + " + ;; + +esac + +printf "" diff --git a/src/wsdiscovery/wsdiscovery/wsdiscovery.c b/src/wsdiscovery/wsdiscovery/wsdiscovery.c new file mode 100755 index 0000000..328200c --- /dev/null +++ b/src/wsdiscovery/wsdiscovery/wsdiscovery.c @@ -0,0 +1,219 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MULTICAST_PORT 3702 +#define MULTICAST_GROUP "239.255.255.250" +#define UUID_SIZE 37 +#define BUF_SIZE 2048 + +int cnt = 1; +char uuid[UUID_SIZE]; +char addressBuffer[INET_ADDRSTRLEN]; +char name[UUID_SIZE]; +char hex[16] = "0123456789abcdef"; + +int check_link(const char *ifname) { + int state = -1; + int socId = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + int rv; + if ((socId < 0) < 0) + perror("Socket failed"); + + struct ifreq if_req; + (void) strncpy(if_req.ifr_name, ifname, sizeof(if_req.ifr_name)); + + if ((rv = ioctl(socId, SIOCGIFFLAGS, &if_req)) == -1) + perror("Ioctl failed"); + + close(socId); + + return (if_req.ifr_flags & IFF_UP) && (if_req.ifr_flags & IFF_RUNNING); +} + +void get_uuid(char *buf) +{ + int i = 0; + while(i < 36) { + /* Format has to be xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx */ + if(i == 8 || i == 13 || i ==18 || i == 23) + buf[i] = '-'; + else if(i == 14) + buf[i] = '4'; + else + buf[i] = hex[rand() % 16]; + ++i; + } +} + +void get_msgid(char *buf) +{ + strcpy(buf, uuid); + int i = 9; + while(i < 36) { + if(i == 13 || i ==18 || i == 23) + buf[i] = '-'; + else if(i == 14) + buf[i] == '4'; + else + buf[i] = hex[rand() % 16]; + ++i; + } +} + +static void signal_callback(int signum) +{ + ++cnt; + int addrlen, bye_sock, family, s; + struct sockaddr_in bye_addr; + + bzero(&bye_addr,sizeof(bye_addr)); + bye_addr.sin_family = AF_INET; + bye_addr.sin_addr.s_addr=htonl(INADDR_ANY); + bye_addr.sin_port = htons(MULTICAST_PORT); + addrlen = sizeof(bye_addr); + + if ((bye_sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket failed"); + exit(1); + } + + char msgid[UUID_SIZE]; + char msgchar[BUF_SIZE]; + get_msgid(msgid); + + /* Send our SOAP Goodbye Mesage */ + bye_addr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP); + sprintf(msgchar, "urn:uuid:%shttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousurn:schemas-xmlsoap-org:ws:2005:04:discoveryhttp://schemas.xmlsoap.org/ws/2005/04/discovery/Byeurn:uuid:%stdn:NetworkVideoTransmitteronvif://www.onvif.org/name/%s onvif://www.onvif.org/Profile/Streaminghttp://%s/onvif/device_service0", msgid, cnt, uuid, name, addressBuffer); + if (sendto(bye_sock, msgchar, strlen(msgchar), 0, (struct sockaddr *) &bye_addr, addrlen) < 0) { + perror("sendto"); + exit(1); + } + + exit(1); +} + +char * extract_between(const char *str, const char *p1, const char *p2) +{ + const char *i1 = strstr(str, p1); + if(i1 != NULL) + { + const size_t pl1 = strlen(p1); + const char *i2 = strstr(i1 + pl1, p2); + if(p2 != NULL) + { + /* Found both markers, extract text. */ + const size_t mlen = i2 - (i1 + pl1); + char *ret = malloc(mlen + 1); + if(ret != NULL) + { + memcpy(ret, i1 + pl1, mlen); + ret[mlen] = '\0'; + return ret; + } + } + } +} + +int main(int argc, const char * argv[]) { + + int addrlen, sock, family, s; + struct sockaddr_in addr; + struct ip_mreq mreq; + struct ifaddrs * ifAddrStruct = NULL; + struct ifaddrs * ifa = NULL; + void * tmpAddrPtr = NULL; + char msgid[UUID_SIZE]; + char msgchar[BUF_SIZE]; + + srand((unsigned int) time(0)); /* Setting Time as random seed */ + strcat(name, argv[2]); + + signal(SIGTERM, signal_callback); /* Handler for Sigterm */ + signal(SIGINT, signal_callback); /* and Sigint */ + + bzero(&addr,sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr=htonl(INADDR_ANY); + addr.sin_port = htons(MULTICAST_PORT); + addrlen = sizeof(addr); + + while (strlen(addressBuffer) == 0) { /* check if we allready have an valid IPv4 address assigned */ + if (getifaddrs(&ifAddrStruct) == -1) + { + perror("getifaddrs"); + exit(1); + } + for (ifa = ifAddrStruct; ifa != NULL; ifa = ifa->ifa_next) { + if ((strcmp(ifa->ifa_name,argv[1])==0)&&ifa ->ifa_addr->sa_family==AF_INET) { /* Check it is a valid IPv4 address */ + tmpAddrPtr = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + inet_ntop(AF_INET, tmpAddrPtr, addressBuffer, INET_ADDRSTRLEN); + } + } + if(strlen(addressBuffer) == 0) /* Sleep for one secound if we still didnt get an valid IPv4 address */ + sleep(1); + } + + if (ifAddrStruct != NULL) + freeifaddrs(ifAddrStruct); + + if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + perror("socket failed"); + exit(1); + } + + if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { + perror("bind failed"); + exit(1); + } + + mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_GROUP); /* Set Multicast IP address */ + mreq.imr_interface.s_addr = inet_addr(addressBuffer); /* Set interface for Multicast subscription */ + if (setsockopt(sock, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) == -1) { + perror("Error joining multicast group"); + exit(1); + } + + get_uuid(uuid); /* Get our UUID for this session */ + get_msgid(msgid); /* Get the first Message ID for this session */ + + /* Send the XML-SOAP Hello message */ + sprintf(msgchar, "urn:uuid:%shttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymousurn:schemas-xmlsoap-org:ws:2005:04:discoveryhttp://schemas.xmlsoap.org/ws/2005/04/discovery/Hellourn:uuid:%stdn:NetworkVideoTransmitteronvif://www.onvif.org/name/%s onvif://www.onvif.org/Profile/Streaminghttp://%s/onvif/device_service0", msgid, cnt, uuid, name, addressBuffer); + addr.sin_addr.s_addr = inet_addr(MULTICAST_GROUP); + if (sendto(sock, msgchar, strlen(msgchar), 0, (struct sockaddr *) &addr, addrlen) < 0) { + perror("sendto"); + exit(1); + } + + while (1) { + char buf[BUF_SIZE] = ""; + + if (recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &addr, &addrlen) < 0) { + perror("recvfrom"); + exit(1); + } + if(strstr(buf, "NetworkVideoTransmitter") && !strstr(buf, "XAddrs")) { + ++cnt; + char msgchar[BUF_SIZE] = ""; + char msgid[UUID_SIZE] = ""; + get_uuid(msgid); /* Get a new Message ID */ + + sprintf(msgchar, "urn:uuid:%s%shttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://schemas.xmlsoap.org/ws/2004/08/addressing/role/anonymoushttp://schemas.xmlsoap.org/ws/2005/04/discovery/ProbeMatchesurn:uuid:%stdn:NetworkVideoTransmitteronvif://www.onvif.org/name/%s onvif://www.onvif.org/Profile/Streaminghttp://%s/onvif/device_service0", msgid, extract_between(buf, "", ""), cnt, uuid, name, addressBuffer ); + if (sendto(sock, msgchar, strlen(msgchar), 0, (struct sockaddr *) &addr, addrlen) < 0) { + perror("sendto"); + exit(1); + } + + } + } +} \ No newline at end of file