Beispiel #1
0
int
dns_encode_a_response(char *buf, size_t buflen, struct query *q)
/* Only used when iodined gets an A type query for ns.topdomain or www.topdomain */
/* Mostly same as dns_encode_ns_response() above */
{
	HEADER *header;
	int len;
	short name;
	char *ipp;
	char *p;

	if (buflen < sizeof(HEADER))
		return 0;

	memset(buf, 0, buflen);

	header = (HEADER*)buf;

	header->id = htons(q->id);
	header->qr = 1;
	header->opcode = 0;
	header->aa = 1;
	header->tc = 0;
	header->rd = 0;
	header->ra = 0;

	p = buf + sizeof(HEADER);

	header->qdcount = htons(1);
	header->ancount = htons(1);

	/* pointer to start of name */
	name = 0xc000 | ((p - buf) & 0x3fff);

	/* Query section */
	putname(&p, buflen - (p - buf), q->name);	/* Name */
	CHECKLEN(4);
	putshort(&p, q->type);			/* Type */
	putshort(&p, C_IN);			/* Class */

	/* Answer section */
	CHECKLEN(12);
	putshort(&p, name);			/* Name */
	putshort(&p, q->type);			/* Type */
	putshort(&p, C_IN);			/* Class */
	putlong(&p, 3600);			/* TTL */
	putshort(&p, 4);			/* Data length */

	/* ugly hack to output IP address */
	ipp = (char *) &q->destination;
	CHECKLEN(4);
	putbyte(&p, *(ipp++));
	putbyte(&p, *(ipp++));
	putbyte(&p, *(ipp++));
	putbyte(&p, *ipp);

	len = p - buf;
	return len;
}
Beispiel #2
0
/* Takes a format argument and a string argument. Interprets data
 * in the string according to the format specification and returns
 * that data.
 *
 * Format characters:
 *   ? = 1 byte of data to be discarded
 *   b = signed byte value
 *   B = unsigned byte value
 *   c = 1-character string
 *   f = 4-byte floating-point value (float)
 *   h = signed 2-byte value (short)
 *   H = unsigned 2-byte value (short)
 *   i = signed 4-byte value (int)
 *   I = unsigned 4-byte value (int)
 *   l = signed 8-byte value (long long)
 *   L = unsigned 8-byte value (long long)
 *   s = string preceded by length (1 byte)
 *   S = string preceded by length (2 bytes)
 *   t = string preceded by length (4 bytes)
 *   v = vector (3 floats totaling 12 bytes)
 *   z = null-terminated string
 */
static int unpack(lua_State *L)
{
	int n;
	size_t len;
	const char *str;
	const char *fmt;

	n = lua_gettop(L);
	if (n != 2)
		return luaL_error(L, "expected 2 arguments for binread function (got %d)", n);
	fmt = luaL_checkstring(L, 1);
	str = luaL_checklstring(L, 2, &len);
	DEBUG(3, "unpack(\"%s\", ...)\n", fmt);
	lua_settop(L, 0);
	n = 0;
	for (; *fmt; fmt++)
	{
		switch (*fmt)
		{
			case '?':
				CHECKLEN(1);
				str = &str[1];
				n--;
				len--;
				break;
			case 'b':
				CHECKLEN(1);
				lua_pushinteger(L, *((signed char *) str));
				str = &str[1];
				len--;
				break;
			case 'B':
				CHECKLEN(1);
				lua_pushinteger(L, *((unsigned char *) str));
				str = &str[1];
				len--;
				break;
			case 'c':
				CHECKLEN(1);
				{
					char c[2] = { str[0], '\0' };
					lua_pushstring(L, c);
				}
				str = &str[1];
				len--;
				break;
			case 'f':
				CHECKLEN(4);
				lua_pushnumber(L, *((float *) str));
				str = &str[4];
				len -= 4;
				break;
			case 'h':
				CHECKLEN(2);
				lua_pushinteger(L, *((short *) str));
				str = &str[2];
				len -= 2;
				break;
			case 'H':
				CHECKLEN(2);
				lua_pushinteger(L, *((unsigned short *) str));
				str = &str[2];
				len -= 2;
				break;
			case 'i':
				CHECKLEN(4);
				lua_pushinteger(L, *((int *) str));
				str = &str[4];
				len -= 4;
				break;
			case 'I':
				CHECKLEN(4);
				lua_pushinteger(L, *((unsigned int *) str));
				str = &str[4];
				len -= 4;
				break;
			case 'l':
				CHECKLEN(8);
				lua_pushnumber(L, *((long long *) str));
				str = &str[8];
				len -= 8;
				break;
			case 'L':
				CHECKLEN(8);
				lua_pushnumber(L, *((unsigned long long *) str));
				str = &str[8];
				len -= 8;
				break;
			case 's':
				CHECKLEN(1);
				{
					unsigned char l = str[0];
					str = &str[1];
					len -= 1;
					CHECKLEN(l);
					lua_pushlstring(L, str, l);
					str = &str[l];
					len -= l;
				}
				break;
			case 'S':
				CHECKLEN(2);
				{
					unsigned short l = *((unsigned short *) str);
					str = &str[2];
					len -= 2;
					CHECKLEN(l);
					lua_pushlstring(L, str, l);
					str = &str[l];
					len -= l;
				}
				break;
			case 't':
				CHECKLEN(4);
				{
					unsigned int l = *((unsigned int *) str);
					str = &str[4];
					len -= 4;
					CHECKLEN(l);
					lua_pushlstring(L, str, l);
					str = &str[l];
					len -= l;
				}
				break;
			case 'v':
				CHECKLEN(12);
				lua_getglobal(L, "vec");
				lua_pushnumber(L, *((float *) str));
				str = &str[4];
				lua_pushnumber(L, *((float *) str));
				str = &str[4];
				lua_pushnumber(L, *((float *) str));
				str = &str[4];
				lua_call(L, 3, 1);
				len -= 12;
				break;
			case 'z':
				CHECKLEN(1);
				{
					int l = strlen(str);
					lua_pushstring(L, str);
					str = &str[l];
					len -= l;
				}
				break;
			default:
				luaL_error(L, "invalid character '%c' in format string", *fmt);
		}
		n++;
	}

	return n;
}
Beispiel #3
0
void iap_handlepkt_mode2(const unsigned int len, const unsigned char *buf)
{
    static bool poweron_pressed = false;
    unsigned int cmd = buf[1];

    /* We expect at least three bytes in the buffer, one for the
     * lingo, one for the command, and one for the first button
     * state bits.
     */
    CHECKLEN(3);

    /* Lingo 0x02 must have been negotiated */
    if (!DEVICE_LINGO_SUPPORTED(0x02)) {
        cmd_ack(cmd, IAP_ACK_BAD_PARAM);
        return;
    }

    switch (cmd)
    {
        /* ContextButtonStatus (0x00)
         *
         * Transmit button events from the device to the iPod
         *
         * Packet format (offset in buf[]: Description)
         * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
         * 0x01: Command, always 0x00
         * 0x02: Button states 0:7
         * 0x03: Button states 8:15 (optional)
         * 0x04: Button states 16:23 (optional)
         * 0x05: Button states 24:31 (optional)
         *
         * Returns: (none)
         */
        case 0x00:
        {
            iap_remotebtn = BUTTON_NONE;
            iap_timeoutbtn = 0;

            if(buf[2] != 0)
            {
                if(buf[2] & 1)
                    REMOTE_BUTTON(BUTTON_RC_PLAY);
                if(buf[2] & 2)
                    REMOTE_BUTTON(BUTTON_RC_VOL_UP);
                if(buf[2] & 4)
                    REMOTE_BUTTON(BUTTON_RC_VOL_DOWN);
                if(buf[2] & 8)
                    REMOTE_BUTTON(BUTTON_RC_RIGHT);
                if(buf[2] & 16)
                    REMOTE_BUTTON(BUTTON_RC_LEFT);
            }
            else if(len >= 4 && buf[3] != 0)
            {
                if(buf[3] & 1) /* play */
                {
                    if (audio_status() != AUDIO_STATUS_PLAY)
                        REMOTE_BUTTON(BUTTON_RC_PLAY);
                }
                if(buf[3] & 2) /* pause */
                {
                    if (audio_status() == AUDIO_STATUS_PLAY)
                        REMOTE_BUTTON(BUTTON_RC_PLAY);
                }
                if(buf[3] & 128) /* Shuffle */
                {
                    if (!iap_btnshuffle)
                    {
                        iap_shuffle_state(!global_settings.playlist_shuffle);
                        iap_btnshuffle = true;
                    }
                }
            }
            else if(len >= 5 && buf[4] != 0)
            {
                if(buf[4] & 1) /* repeat */
                {
                    if (!iap_btnrepeat)
                    {
                        iap_repeat_next();
                        iap_btnrepeat = true;
                    }
                }

                if (buf[4] & 2) /* power on */
                {
                    poweron_pressed = true;
                }

                /* Power off
                 * Not quite sure how to react to this, but stopping playback
                 * is a good start.
                 */
                if (buf[4] & 0x04)
                {
                    if (audio_status() == AUDIO_STATUS_PLAY)
                        REMOTE_BUTTON(BUTTON_RC_PLAY);
                }

                if(buf[4] & 16) /* ffwd */
                    REMOTE_BUTTON(BUTTON_RC_RIGHT);
                if(buf[4] & 32) /* frwd */
                    REMOTE_BUTTON(BUTTON_RC_LEFT);
            }

            /* power on released */
            if (poweron_pressed && len >= 5 && !(buf[4] & 2))
            {
                poweron_pressed = false;
#ifdef HAVE_LINE_REC
                /* Belkin TuneTalk microphone sends power-on press+release
                 * events once authentication sequence is finished,
                 * GetDevCaps command is ignored by the device when it is
                 * sent before power-on release event is received.
                 * XXX: It is unknown if other microphone devices are
                 * sending the power-on events.
                 */
                if (DEVICE_LINGO_SUPPORTED(0x01)) {
                    /* GetDevCaps */
                    IAP_TX_INIT(0x01, 0x07);
                    iap_send_tx();
                }
#endif
            }

            break;
        }
        /* ACK (0x01)
         *
         * Sent from the iPod to the device
         */

        /* ImageButtonStatus (0x02)
         *
         * Transmit image button events from the device to the iPod
         *
         * Packet format (offset in buf[]: Description)
         * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
         * 0x01: Command, always 0x02
         * 0x02: Button states 0:7
         * 0x03: Button states 8:15 (optional)
         * 0x04: Button states 16:23 (optional)
         * 0x05: Button states 24:31 (optional)
         *
         * This command requires authentication
         *
         * Returns on success:
         * IAP_ACK_OK
         *
         * Returns on failure:
         * IAP_ACK_*
         */
        case 0x02:
        {
            if (!DEVICE_AUTHENTICATED) {
                cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
                break;
            }

            cmd_ack(cmd, IAP_ACK_CMD_FAILED);
            break;
        }

        /* VideoButtonStatus (0x03)
         *
         * Transmit video button events from the device to the iPod
         *
         * Packet format (offset in buf[]: Description)
         * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
         * 0x01: Command, always 0x03
         * 0x02: Button states 0:7
         * 0x03: Button states 8:15 (optional)
         * 0x04: Button states 16:23 (optional)
         * 0x05: Button states 24:31 (optional)
         *
         * This command requires authentication
         *
         * Returns on success:
         * IAP_ACK_OK
         *
         * Returns on failure:
         * IAP_ACK_*
         */
        case 0x03:
        {
            if (!DEVICE_AUTHENTICATED) {
                cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
                break;
            }

            cmd_ack(cmd, IAP_ACK_CMD_FAILED);
            break;
        }

        /* AudioButtonStatus (0x04)
         *
         * Transmit audio button events from the device to the iPod
         *
         * Packet format (offset in buf[]: Description)
         * 0x00: Lingo ID: Simple Remote Lingo, always 0x02
         * 0x01: Command, always 0x04
         * 0x02: Button states 0:7
         * 0x03: Button states 8:15 (optional)
         * 0x04: Button states 16:23 (optional)
         * 0x05: Button states 24:31 (optional)
         *
         * This command requires authentication
         *
         * Returns on success:
         * IAP_ACK_OK
         *
         * Returns on failure:
         * IAP_ACK_*
         */
        case 0x04:
        {
            unsigned char repeatbuf[6];

            if (!DEVICE_AUTHENTICATED) {
                cmd_ack(cmd, IAP_ACK_NO_AUTHEN);
                break;
            }

            /* This is basically the same command as ContextButtonStatus (0x00),
             * with the difference that it requires authentication and that
             * it returns an ACK packet to the device.
             * So just route it through the handler again, with 0x00 as the
             * command
             */
            memcpy(repeatbuf, buf, 6);
            repeatbuf[1] = 0x00;
            iap_handlepkt_mode2((len<6)?len:6, repeatbuf);

            cmd_ok(cmd);
            break;
        }

        /* The default response is IAP_ACK_BAD_PARAM */
        default:
        {
#ifdef LOGF_ENABLE
            logf("iap: Unsupported Mode02 Command");
#else
            cmd_ack(cmd, IAP_ACK_BAD_PARAM);
#endif
            break;
        }
    }
}
Beispiel #4
0
int
dns_encode(char *buf, size_t buflen, struct query *q, qr_t qr, char *data, size_t datalen)
{
	HEADER *header;
	short name;
	char *p;
	int len;
	int ancnt;

	if (buflen < sizeof(HEADER))
		return 0;

	memset(buf, 0, buflen);

	header = (HEADER*)buf;

	header->id = htons(q->id);
	header->qr = (qr == QR_ANSWER);
	header->opcode = 0;
	header->aa = (qr == QR_ANSWER);
	header->tc = 0;
	header->rd = (qr == QR_QUERY);
	header->ra = 0;

	p = buf + sizeof(HEADER);

	switch (qr) {
	case QR_ANSWER:
		header->qdcount = htons(1);

		name = 0xc000 | ((p - buf) & 0x3fff);

		/* Question section */
		putname(&p, buflen - (p - buf), q->name);

		CHECKLEN(4);
		putshort(&p, q->type);
		putshort(&p, C_IN);

		/* Answer section */

		if (q->type == T_CNAME || q->type == T_A ||
			q->type == T_PTR || q->type == T_AAAA ||
			q->type == T_A6 || q->type == T_DNAME) {
			/* data is expected to be like "Hblabla.host.name.com\0" */

			char *startp;
			int namelen;

			CHECKLEN(10);
			putshort(&p, name);
			if (q->type == T_A || q->type == T_AAAA)
				/* answer CNAME to A question */
				putshort(&p, T_CNAME);
			else
				putshort(&p, q->type);
			putshort(&p, C_IN);
			putlong(&p, 0);		/* TTL */

			startp = p;
			p += 2;			/* skip 2 bytes length */
			if (q->type == T_A6) {
				CHECKLEN(1);
				putbyte(&p, 128);
			}
			putname(&p, buflen - (p - buf), data);
			CHECKLEN(0);
			namelen = p - startp;
			namelen -= 2;
			putshort(&startp, namelen);
			ancnt = 1;
		} else if (q->type == T_MX || q->type == T_SRV) {
			/* Data is expected to be like
			   "Hblabla.host.name.com\0Hanother.com\0\0"
			   For SRV, see RFC2782.
			 */

			char *mxdata = data;
			char *startp;
			int namelen;

			ancnt = 1;
			while (1) {
				CHECKLEN(10);
				putshort(&p, name);
				putshort(&p, q->type);
				putshort(&p, C_IN);
				putlong(&p, 0);		/* TTL */

				startp = p;
				p += 2;			/* skip 2 bytes length */
				CHECKLEN(2);
				putshort(&p, 10 * ancnt);	/* preference */

				if (q->type == T_SRV) {
					/* weight, port (5060 = SIP) */
					CHECKLEN(4);
					putshort(&p, 10);
					putshort(&p, 5060);
				}

				putname(&p, buflen - (p - buf), mxdata);
				CHECKLEN(0);
				namelen = p - startp;
				namelen -= 2;
				putshort(&startp, namelen);

				mxdata = mxdata + strlen(mxdata) + 1;
				if (*mxdata == '\0')
					break;

				ancnt++;
			}
		} else if (q->type == T_TXT) {
			/* TXT has binary or base-X data */
			char *startp;
			int txtlen;

			CHECKLEN(10);
			putshort(&p, name);
			putshort(&p, q->type);
			putshort(&p, C_IN);
			putlong(&p, 0);		/* TTL */

			startp = p;
			p += 2;			/* skip 2 bytes length */
			puttxtbin(&p, buflen - (p - buf), data, datalen);
			CHECKLEN(0);
			txtlen = p - startp;
			txtlen -= 2;
			putshort(&startp, txtlen);
			ancnt = 1;
		} else {
			/* NULL has raw binary data */

			CHECKLEN(10);
			putshort(&p, name);
			putshort(&p, q->type);
			putshort(&p, C_IN);
			putlong(&p, 0);		/* TTL */

			datalen = MIN(datalen, buflen - (p - buf));
			CHECKLEN(2);
			putshort(&p, datalen);
			CHECKLEN(datalen);
			putdata(&p, data, datalen);
			CHECKLEN(0);
			ancnt = 1;
		}
		header->ancount = htons(ancnt);
		break;
	case QR_QUERY:
		/* Note that iodined also uses this for forward queries */

		header->qdcount = htons(1);

		datalen = MIN(datalen, buflen - (p - buf));
		putname(&p, datalen, data);

		CHECKLEN(4);
		putshort(&p, q->type);
		putshort(&p, C_IN);

		/* EDNS0 to advertise maximum response length
		   (even CNAME/A/MX, 255+255+header would be >512) */
		if (dnsc_use_edns0) {
			header->arcount = htons(1);
			CHECKLEN(11);
			putbyte(&p, 0x00);    /* Root */
			putshort(&p, 0x0029); /* OPT */
			putshort(&p, 0x1000); /* Payload size: 4096 */
			putshort(&p, 0x0000); /* Higher bits/edns version */
			putshort(&p, 0x8000); /* Z */
			putshort(&p, 0x0000); /* Data length */
		}

		break;
	}

	len = p - buf;

	return len;
}
Beispiel #5
0
int
dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet, size_t packetlen)
{
	char name[QUERY_NAME_SIZE];
	char rdata[4*1024];
	HEADER *header;
	short qdcount;
	short ancount;
	uint32_t ttl;
	unsigned short class;
	unsigned short type;
	char *data;
	unsigned short rlen;
	uint16_t id;
	int rv;

	rv = 0;
	header = (HEADER*)packet;

	/* Reject short packets */
	if (packetlen < sizeof(HEADER))
		return 0;

	if (header->qr != qr) {
		warnx("header->qr does not match the requested qr");
		return -1;
	}

	data = packet + sizeof(HEADER);
	qdcount = ntohs(header->qdcount);
	ancount = ntohs(header->ancount);

	id = ntohs(header->id);

	rlen = 0;

	if (q != NULL)
		q->rcode = header->rcode;

	switch (qr) {
	case QR_ANSWER:
		if(qdcount < 1) {
			/* We need a question */
			return -1;
		}

		if (q != NULL)
			q->id = id;

		/* Read name even if no answer, to give better error message */
		readname(packet, packetlen, &data, name, sizeof(name));
		CHECKLEN(4);
		readshort(packet, &data, &type);
		readshort(packet, &data, &class);

		/* if CHECKLEN okay, then we're sure to have a proper name */
		if (q != NULL) {
			/* We only need the first char to check it */
			q->name[0] = name[0];
			q->name[1] = '\0';
		}

		if (ancount < 1) {
			/* DNS errors like NXDOMAIN have ancount=0 and
			   stop here. CNAME may also have A; MX/SRV may have
			   multiple results. */
			return -1;
		}

		/* Here type is still the question type */
		if (type == T_NULL || type == T_PRIVATE) {
			/* Assume that first answer is what we wanted */
			readname(packet, packetlen, &data, name, sizeof(name));
			CHECKLEN(10);
			readshort(packet, &data, &type);
			readshort(packet, &data, &class);
			readlong(packet, &data, &ttl);
			readshort(packet, &data, &rlen);

			rv = MIN(rlen, sizeof(rdata));
			rv = readdata(packet, &data, rdata, rv);
			if (rv >= 2 && buf) {
				rv = MIN(rv, buflen);
				memcpy(buf, rdata, rv);
			} else {
				rv = 0;
			}
		}
		else if ((type == T_A || type == T_CNAME ||
Beispiel #6
0
int
dns_encode_ns_response(char *buf, size_t buflen, struct query *q, char *topdomain)
/* Only used when iodined gets an NS type query */
/* Mostly same as dns_encode_a_response() below */
{
	HEADER *header;
	int len;
	short name;
	short topname;
	short nsname;
	char *ipp;
	int domain_len;
	char *p;

	if (buflen < sizeof(HEADER))
		return 0;

	memset(buf, 0, buflen);

	header = (HEADER*)buf;

	header->id = htons(q->id);
	header->qr = 1;
	header->opcode = 0;
	header->aa = 1;
	header->tc = 0;
	header->rd = 0;
	header->ra = 0;

	p = buf + sizeof(HEADER);

	header->qdcount = htons(1);
	header->ancount = htons(1);
	header->arcount = htons(1);

	/* pointer to start of name */
	name = 0xc000 | ((p - buf) & 0x3fff);

	domain_len = strlen(q->name) - strlen(topdomain);
	if (domain_len < 0 || domain_len == 1)
		return -1;
	if (strcasecmp(q->name + domain_len, topdomain))
		return -1;
	if (domain_len >= 1 && q->name[domain_len - 1] != '.')
		return -1;

	/* pointer to start of topdomain; instead of dots at the end
	   we have length-bytes in front, so total length is the same */
	topname = 0xc000 | ((p - buf + domain_len) & 0x3fff);

	/* Query section */
	putname(&p, buflen - (p - buf), q->name);	/* Name */
	CHECKLEN(4);
	putshort(&p, q->type);			/* Type */
	putshort(&p, C_IN);			/* Class */

	/* Answer section */
	CHECKLEN(12);
	putshort(&p, name);			/* Name */
	putshort(&p, q->type);			/* Type */
	putshort(&p, C_IN);			/* Class */
	putlong(&p, 3600);			/* TTL */
	putshort(&p, 5);			/* Data length */

	/* pointer to ns.topdomain */
	nsname = 0xc000 | ((p - buf) & 0x3fff);
	CHECKLEN(5);
	putbyte(&p, 2);
	putbyte(&p, 'n');
	putbyte(&p, 's');
	putshort(&p, topname);			/* Name Server */

	/* Additional data (A-record of NS server) */
	CHECKLEN(12);
	putshort(&p, nsname);			/* Name Server */
	putshort(&p, T_A);			/* Type */
	putshort(&p, C_IN);			/* Class */
	putlong(&p, 3600);			/* TTL */
	putshort(&p, 4);			/* Data length */

	/* ugly hack to output IP address */
	ipp = (char *) &q->destination;
	CHECKLEN(4);
	putbyte(&p, *(ipp++));
	putbyte(&p, *(ipp++));
	putbyte(&p, *(ipp++));
	putbyte(&p, *ipp);

	len = p - buf;
	return len;
}