|
|
/*------------------------------------------------------------------------------
|
|
|
-- This file is a part of the QLop Software
|
|
|
-- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
|
|
|
--
|
|
|
-- 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 of the License, 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 this program; if not, write to the Free Software
|
|
|
-- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
-------------------------------------------------------------------------------*/
|
|
|
/*-- Author : Alexis Jeandet
|
|
|
-- Mail : alexis.jeandet@member.fsf.org
|
|
|
----------------------------------------------------------------------------*/
|
|
|
// based on Based on qt-examples: https://gitorious.org/qt-examples/qt-examples/blobs/master/pac-files
|
|
|
// and also KDE's KIO kpac source code: https://projects.kde.org/projects/frameworks/kio/repository/revisions/master/show/src/kpac
|
|
|
// specially https://projects.kde.org/projects/frameworks/kio/repository/revisions/master/entry/src/kpac/script.cpp
|
|
|
|
|
|
#include "proxypacparser.h"
|
|
|
#include <QHostAddress>
|
|
|
#include <QHostInfo>
|
|
|
#include <QNetworkInterface>
|
|
|
#include <QDateTime>
|
|
|
|
|
|
|
|
|
class Address
|
|
|
{
|
|
|
public:
|
|
|
struct Error {};
|
|
|
static Address resolve(const QString &host)
|
|
|
{
|
|
|
return Address(host);
|
|
|
}
|
|
|
|
|
|
QList<QHostAddress> addresses() const
|
|
|
{
|
|
|
return m_addressList;
|
|
|
}
|
|
|
|
|
|
QHostAddress address() const
|
|
|
{
|
|
|
if (m_addressList.isEmpty()) {
|
|
|
return QHostAddress();
|
|
|
}
|
|
|
|
|
|
return m_addressList.first();
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
Address(const QString &host)
|
|
|
{
|
|
|
// Always try to see if it's already an IP first, to avoid Qt doing a
|
|
|
// needless reverse lookup
|
|
|
QHostAddress address(host);
|
|
|
if (address.isNull()) {
|
|
|
QHostInfo hostInfo;
|
|
|
if (hostInfo.hostName().isEmpty() || hostInfo.error() != QHostInfo::NoError) {
|
|
|
hostInfo = QHostInfo::fromName(host);
|
|
|
}
|
|
|
m_addressList = hostInfo.addresses();
|
|
|
} else {
|
|
|
m_addressList.clear();
|
|
|
m_addressList.append(address);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QList<QHostAddress> m_addressList;
|
|
|
};
|
|
|
|
|
|
ProxyPacParser::ProxyPacParser(QObject *parent)
|
|
|
{
|
|
|
engine = new QScriptEngine(this);
|
|
|
QScriptValue globalObject = engine->globalObject();
|
|
|
|
|
|
globalObject.setProperty(QString("isPlainHostName"), engine->newFunction(isPlainHostName));
|
|
|
globalObject.setProperty(QString("dnsDomainIs"), engine->newFunction(dnsDomainIs));
|
|
|
globalObject.setProperty(QString("localHostOrDomainIs"), engine->newFunction(localHostOrDomainIs));
|
|
|
globalObject.setProperty(QString("isResolvable"), engine->newFunction(isResolvable));
|
|
|
globalObject.setProperty(QString("isInNet"), engine->newFunction(isInNet));
|
|
|
|
|
|
//Related utility functions:
|
|
|
globalObject.setProperty(QString("dnsResolve"), engine->newFunction(dnsResolve));
|
|
|
globalObject.setProperty(QString("myIpAddress"), engine->newFunction(myIpAddress));
|
|
|
globalObject.setProperty(QString("dnsDomainLevels"), engine->newFunction(dnsDomainLevels));
|
|
|
|
|
|
//URL/hostname based conditions:
|
|
|
globalObject.setProperty(QString("shExpMatch"), engine->newFunction(shExpMatch));
|
|
|
|
|
|
// Time based conditions:
|
|
|
globalObject.setProperty(QString("weekdayRange"), engine->newFunction(weekdayRange));
|
|
|
globalObject.setProperty(QString("dateRange"), engine->newFunction(dateRange));
|
|
|
globalObject.setProperty(QString("timeRange"), engine->newFunction(timeRange));
|
|
|
|
|
|
//Implementation of Microsoft's IPv6 Extension for PAC
|
|
|
globalObject.setProperty(QString("isResolvableEx"), engine->newFunction(isResolvableEx));
|
|
|
globalObject.setProperty(QString("isInNetEx"), engine->newFunction(isInNetEx));
|
|
|
globalObject.setProperty(QString("dnsResolveEx"), engine->newFunction(dnsResolveEx));
|
|
|
globalObject.setProperty(QString("myIpAddressEx"), engine->newFunction(myIpAddressEx));
|
|
|
globalObject.setProperty(QString("sortIpAddressList"), engine->newFunction(sortIpAddressList));
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
ProxyPacParser::~ProxyPacParser()
|
|
|
{
|
|
|
// delete engine;
|
|
|
}
|
|
|
|
|
|
void ProxyPacParser::setPacFile(const QString &fileContent)
|
|
|
{
|
|
|
engine->evaluate(fileContent);
|
|
|
}
|
|
|
|
|
|
QString ProxyPacParser::findProxyForUrl(const QString &url, const QString &host)
|
|
|
{
|
|
|
QScriptValue global = engine->globalObject();
|
|
|
QScriptValue fun = global.property("FindProxyForURL");
|
|
|
if ( !fun.isFunction() ) {
|
|
|
return QString("DIRECT");
|
|
|
}
|
|
|
|
|
|
QScriptValueList args;
|
|
|
args << engine->toScriptValue( url ) << engine->toScriptValue( host );
|
|
|
|
|
|
QScriptValue val = fun.call( global, args );
|
|
|
|
|
|
return val.toString();
|
|
|
}
|
|
|
|
|
|
template <typename T>
|
|
|
static bool checkRange(T value, T min, T max)
|
|
|
{
|
|
|
return ((min <= max && value >= min && value <= max) ||
|
|
|
(min > max && (value <= min || value >= max)));
|
|
|
}
|
|
|
|
|
|
|
|
|
static bool isLocalHostAddress(const QHostAddress &address)
|
|
|
{
|
|
|
if (address == QHostAddress::LocalHost) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if (address == QHostAddress::LocalHostIPv6) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
static bool isIPv6Address(const QHostAddress &address)
|
|
|
{
|
|
|
return address.protocol() == QAbstractSocket::IPv6Protocol;
|
|
|
}
|
|
|
|
|
|
static bool isIPv4Address(const QHostAddress &address)
|
|
|
{
|
|
|
return (address.protocol() == QAbstractSocket::IPv4Protocol);
|
|
|
}
|
|
|
|
|
|
static bool isSpecialAddress(const QHostAddress &address)
|
|
|
{
|
|
|
// Catch all the special addresses and return false.
|
|
|
if (address == QHostAddress::Null) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if (address == QHostAddress::Any) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if (address == QHostAddress::AnyIPv6) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
if (address == QHostAddress::Broadcast) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
|
|
|
static bool addressLessThanComparison(const QHostAddress &addr1, const QHostAddress &addr2)
|
|
|
{
|
|
|
if (addr1.protocol() == QAbstractSocket::IPv4Protocol &&
|
|
|
addr2.protocol() == QAbstractSocket::IPv4Protocol) {
|
|
|
return addr1.toIPv4Address() < addr2.toIPv4Address();
|
|
|
}
|
|
|
|
|
|
if (addr1.protocol() == QAbstractSocket::IPv6Protocol &&
|
|
|
addr2.protocol() == QAbstractSocket::IPv6Protocol) {
|
|
|
const Q_IPV6ADDR ipv6addr1 = addr1.toIPv6Address();
|
|
|
const Q_IPV6ADDR ipv6addr2 = addr2.toIPv6Address();
|
|
|
for (int i = 0; i < 16; ++i) {
|
|
|
if (ipv6addr1[i] != ipv6addr2[i]) {
|
|
|
return ((ipv6addr1[i] & 0xff) - (ipv6addr2[i] & 0xff));
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
static QString addressListToString(const QList<QHostAddress> &addressList,
|
|
|
const QHash<QString, QString> &actualEntryMap)
|
|
|
{
|
|
|
QString result;
|
|
|
Q_FOREACH (const QHostAddress &address, addressList) {
|
|
|
if (!result.isEmpty()) {
|
|
|
result += QLatin1Char(';');
|
|
|
}
|
|
|
result += actualEntryMap.value(address.toString());
|
|
|
}
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
const QDateTime ProxyPacParser::getTime(QScriptContext *context)
|
|
|
{
|
|
|
const QString tz = context->argument(context->argumentCount() - 1).toString();
|
|
|
if (tz.compare(QLatin1String("gmt"), Qt::CaseInsensitive) == 0) {
|
|
|
return QDateTime::currentDateTimeUtc();
|
|
|
}
|
|
|
return QDateTime::currentDateTime();
|
|
|
}
|
|
|
|
|
|
int ProxyPacParser::findString(const QString &s, const char *const *values)
|
|
|
{
|
|
|
int index = 0;
|
|
|
const QString lower = s.toLower();
|
|
|
for (const char *const *p = values; *p; ++p, ++index) {
|
|
|
if (s.compare(QLatin1String(*p), Qt::CaseInsensitive) == 0) {
|
|
|
return index;
|
|
|
}
|
|
|
}
|
|
|
return -1;
|
|
|
}
|
|
|
|
|
|
QScriptValue ProxyPacParser::myIpAddress(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if ( context->argumentCount() != 0 )
|
|
|
return context->throwError("myIpAddress takes no arguments");
|
|
|
|
|
|
foreach( QHostAddress address, QNetworkInterface::allAddresses() ) {
|
|
|
if ( address != QHostAddress::LocalHost
|
|
|
&& address != QHostAddress::LocalHostIPv6 )
|
|
|
return QScriptValue( engine, address.toString() );
|
|
|
}
|
|
|
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
// dnsDomainLevels(host)
|
|
|
// @returns the number of dots ('.') in @p host
|
|
|
QScriptValue ProxyPacParser::dnsDomainLevels(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
const QString host = context->argument(0).toString();
|
|
|
if (host.isNull()) {
|
|
|
return engine->toScriptValue(0);
|
|
|
}
|
|
|
return engine->toScriptValue(host.count(QLatin1Char('.')));
|
|
|
}
|
|
|
|
|
|
QScriptValue ProxyPacParser::isInNet(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if ( context->argumentCount() != 3 )
|
|
|
return context->throwError("isInNet takes three arguments");
|
|
|
|
|
|
QHostAddress addr( context->argument(0).toString() );
|
|
|
QHostAddress netaddr( context->argument(1).toString() );
|
|
|
QHostAddress netmask( context->argument(2).toString() );
|
|
|
|
|
|
if ( (netaddr.toIPv4Address() & netmask.toIPv4Address()) == (addr.toIPv4Address() & netmask.toIPv4Address()) )
|
|
|
return QScriptValue( engine, true );
|
|
|
|
|
|
return QScriptValue( engine, false );
|
|
|
}
|
|
|
|
|
|
QScriptValue ProxyPacParser::shExpMatch(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if ( context->argumentCount() != 2 )
|
|
|
return context->throwError("shExpMatch takes two arguments");
|
|
|
|
|
|
QRegExp re( context->argument(1).toString(), Qt::CaseSensitive, QRegExp::Wildcard );
|
|
|
if ( re.exactMatch( context->argument(0).toString() ) )
|
|
|
return QScriptValue( engine, true );
|
|
|
|
|
|
return QScriptValue( engine, false );
|
|
|
}
|
|
|
|
|
|
// weekdayRange(day [, "GMT" ])
|
|
|
// weekdayRange(day1, day2 [, "GMT" ])
|
|
|
// @returns true if the current day equals day or between day1 and day2 resp.
|
|
|
// If the last argument is "GMT", GMT timezone is used, otherwise local time
|
|
|
QScriptValue ProxyPacParser::weekdayRange(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() < 1 || context->argumentCount() > 3) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
static const char *const days[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat", 0 };
|
|
|
|
|
|
const int d1 = findString(context->argument(0).toString(), days);
|
|
|
if (d1 == -1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
int d2 = findString(context->argument(1).toString(), days);
|
|
|
if (d2 == -1) {
|
|
|
d2 = d1;
|
|
|
}
|
|
|
|
|
|
// Adjust the days of week coming from QDateTime since it starts
|
|
|
// counting with Monday as 1 and ends with Sunday as day 7.
|
|
|
int dayOfWeek = getTime(context).date().dayOfWeek();
|
|
|
if (dayOfWeek == 7) {
|
|
|
dayOfWeek = 0;
|
|
|
}
|
|
|
return engine->toScriptValue(checkRange(dayOfWeek, d1, d2));
|
|
|
}
|
|
|
|
|
|
// dateRange(day [, "GMT" ])
|
|
|
// dateRange(day1, day2 [, "GMT" ])
|
|
|
// dateRange(month [, "GMT" ])
|
|
|
// dateRange(month1, month2 [, "GMT" ])
|
|
|
// dateRange(year [, "GMT" ])
|
|
|
// dateRange(year1, year2 [, "GMT" ])
|
|
|
// dateRange(day1, month1, day2, month2 [, "GMT" ])
|
|
|
// dateRange(month1, year1, month2, year2 [, "GMT" ])
|
|
|
// dateRange(day1, month1, year1, day2, month2, year2 [, "GMT" ])
|
|
|
// @returns true if the current date (GMT or local time according to
|
|
|
// presence of "GMT" as last argument) is within the given range
|
|
|
QScriptValue ProxyPacParser::dateRange(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() < 1 || context->argumentCount() > 7) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
static const char *const months[] = { "jan", "feb", "mar", "apr", "may", "jun",
|
|
|
"jul", "aug", "sep", "oct", "nov", "dec", 0
|
|
|
};
|
|
|
|
|
|
QVector<int> values;
|
|
|
for (int i = 0; i < context->argumentCount(); ++i) {
|
|
|
int value = -1;
|
|
|
if (context->argument(i).isNumber()) {
|
|
|
value = context->argument(i).toInt32();
|
|
|
} else {
|
|
|
// QDate starts counting months from 1, so we add 1 here.
|
|
|
value = findString(context->argument(i).toString(), months) + 1;
|
|
|
}
|
|
|
|
|
|
if (value > 0) {
|
|
|
values.append(value);
|
|
|
} else {
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
const QDate now = getTime(context).date();
|
|
|
|
|
|
// day1, month1, year1, day2, month2, year2
|
|
|
if (values.size() == 6) {
|
|
|
const QDate d1(values[2], values[1], values[0]);
|
|
|
const QDate d2(values[5], values[4], values[3]);
|
|
|
return engine->toScriptValue(checkRange(now, d1, d2));
|
|
|
}
|
|
|
// day1, month1, day2, month2
|
|
|
else if (values.size() == 4 && values[ 1 ] < 13 && values[ 3 ] < 13) {
|
|
|
const QDate d1(now.year(), values[1], values[0]);
|
|
|
const QDate d2(now.year(), values[3], values[2]);
|
|
|
return engine->toScriptValue(checkRange(now, d1, d2));
|
|
|
}
|
|
|
// month1, year1, month2, year2
|
|
|
else if (values.size() == 4) {
|
|
|
const QDate d1(values[1], values[0], now.day());
|
|
|
const QDate d2(values[3], values[2], now.day());
|
|
|
return engine->toScriptValue(checkRange(now, d1, d2));
|
|
|
}
|
|
|
// year1, year2
|
|
|
else if (values.size() == 2 && values[0] >= 1000 && values[1] >= 1000) {
|
|
|
return engine->toScriptValue(checkRange(now.year(), values[0], values[1]));
|
|
|
}
|
|
|
// day1, day2
|
|
|
else if (values.size() == 2 && context->argument(0).isNumber() && context->argument(1).isNumber()) {
|
|
|
return engine->toScriptValue(checkRange(now.day(), values[0], values[1]));
|
|
|
}
|
|
|
// month1, month2
|
|
|
else if (values.size() == 2) {
|
|
|
return engine->toScriptValue(checkRange(now.month(), values[0], values[1]));
|
|
|
}
|
|
|
// year
|
|
|
else if (values.size() == 1 && values[ 0 ] >= 1000) {
|
|
|
return engine->toScriptValue(checkRange(now.year(), values[0], values[0]));
|
|
|
}
|
|
|
// day
|
|
|
else if (values.size() == 1 && context->argument(0).isNumber()) {
|
|
|
return engine->toScriptValue(checkRange(now.day(), values[0], values[0]));
|
|
|
}
|
|
|
// month
|
|
|
else if (values.size() == 1) {
|
|
|
return engine->toScriptValue(checkRange(now.month(), values[0], values[0]));
|
|
|
}
|
|
|
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
// timeRange(hour [, "GMT" ])
|
|
|
// timeRange(hour1, hour2 [, "GMT" ])
|
|
|
// timeRange(hour1, min1, hour2, min2 [, "GMT" ])
|
|
|
// timeRange(hour1, min1, sec1, hour2, min2, sec2 [, "GMT" ])
|
|
|
// @returns true if the current time (GMT or local based on presence
|
|
|
// of "GMT" argument) is within the given range
|
|
|
QScriptValue ProxyPacParser::timeRange(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() < 1 || context->argumentCount() > 7) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
QVector<int> values;
|
|
|
for (int i = 0; i < context->argumentCount(); ++i) {
|
|
|
if (!context->argument(i).isNumber()) {
|
|
|
break;
|
|
|
}
|
|
|
values.append(context->argument(i).toNumber());
|
|
|
}
|
|
|
|
|
|
const QTime now = getTime(context).time();
|
|
|
|
|
|
// hour1, min1, sec1, hour2, min2, sec2
|
|
|
if (values.size() == 6) {
|
|
|
const QTime t1(values[0], values[1], values[2]);
|
|
|
const QTime t2(values[3], values[4], values[5]);
|
|
|
return engine->toScriptValue(checkRange(now, t1, t2));
|
|
|
}
|
|
|
// hour1, min1, hour2, min2
|
|
|
else if (values.size() == 4) {
|
|
|
const QTime t1(values[0], values[1]);
|
|
|
const QTime t2(values[2], values[3]);
|
|
|
return engine->toScriptValue(checkRange(now, t1, t2));
|
|
|
}
|
|
|
// hour1, hour2
|
|
|
else if (values.size() == 2) {
|
|
|
return engine->toScriptValue(checkRange(now.hour(), values[0], values[1]));
|
|
|
}
|
|
|
// hour
|
|
|
else if (values.size() == 1) {
|
|
|
return engine->toScriptValue(checkRange(now.hour(), values[0], values[0]));
|
|
|
}
|
|
|
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
QScriptValue ProxyPacParser::dnsResolve(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if ( context->argumentCount() != 1 )
|
|
|
return context->throwError("dnsResolve takes one arguments");
|
|
|
|
|
|
QHostInfo info = QHostInfo::fromName( context->argument(0).toString() );
|
|
|
QList<QHostAddress> addresses = info.addresses();
|
|
|
if ( addresses.isEmpty() )
|
|
|
return engine->nullValue(); // TODO: Should this be undefined or an exception? check other implementations
|
|
|
|
|
|
return QScriptValue( engine, addresses.first().toString() );
|
|
|
}
|
|
|
|
|
|
QScriptValue ProxyPacParser::dnsDomainIs(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if ( context->argumentCount() != 2 )
|
|
|
return context->throwError("dnsDomainIs takes two arguments");
|
|
|
|
|
|
QHostInfo info = QHostInfo::fromName( context->argument(0).toString() );
|
|
|
QString domain = info.localDomainName();
|
|
|
QString argDomain = context->argument(1).toString();
|
|
|
|
|
|
if ( !domain.compare(argDomain) || !argDomain.compare("."+domain))
|
|
|
return QScriptValue( engine, true );
|
|
|
return QScriptValue( engine, false);
|
|
|
}
|
|
|
|
|
|
// localHostOrDomainIs(host, fqdn)
|
|
|
// @returns true if @p host is unqualified or equals @p fqdn
|
|
|
QScriptValue ProxyPacParser::localHostOrDomainIs(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 2) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
const QString host = context->argument(0).toString();
|
|
|
if (!host.contains(QLatin1Char('.'))) {
|
|
|
return engine->toScriptValue(true);
|
|
|
}
|
|
|
const QString fqdn = context->argument(1).toString();
|
|
|
return engine->toScriptValue((host.compare(fqdn, Qt::CaseInsensitive) == 0));
|
|
|
}
|
|
|
|
|
|
// isResolvable(host)
|
|
|
// @returns true if host is resolvable to a IPv4 address.
|
|
|
QScriptValue ProxyPacParser::isResolvable(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const Address info = Address::resolve(context->argument(0).toString());
|
|
|
bool hasResolvableIPv4Address = false;
|
|
|
|
|
|
Q_FOREACH (const QHostAddress &address, info.addresses()) {
|
|
|
if (!isSpecialAddress(address) && isIPv4Address(address)) {
|
|
|
hasResolvableIPv4Address = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return engine->toScriptValue(hasResolvableIPv4Address);
|
|
|
} catch (const Address::Error &) {
|
|
|
return engine->toScriptValue(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// isPlainHostName(host)
|
|
|
// @returns true if @p host doesn't contains a domain part
|
|
|
QScriptValue ProxyPacParser::isPlainHostName(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
return engine->toScriptValue(context->argument(0).toString().indexOf(QLatin1Char('.')) == -1);
|
|
|
}
|
|
|
|
|
|
|
|
|
// isResolvableEx(host)
|
|
|
// @returns true if host is resolvable to an IPv4 or IPv6 address.
|
|
|
QScriptValue ProxyPacParser::isResolvableEx(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const Address info = Address::resolve(context->argument(0).toString());
|
|
|
bool hasResolvableIPAddress = false;
|
|
|
Q_FOREACH (const QHostAddress &address, info.addresses()) {
|
|
|
if (isIPv4Address(address) || isIPv6Address(address)) {
|
|
|
hasResolvableIPAddress = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return engine->toScriptValue(hasResolvableIPAddress);
|
|
|
} catch (const Address::Error &) {
|
|
|
return engine->toScriptValue(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// isInNetEx(ipAddress, ipPrefix )
|
|
|
// @returns true if ipAddress is within the specified ipPrefix.
|
|
|
QScriptValue ProxyPacParser::isInNetEx(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 2) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const Address info = Address::resolve(context->argument(0).toString());
|
|
|
bool isInSubNet = false;
|
|
|
const QString subnetStr = context->argument(1).toString();
|
|
|
const QPair<QHostAddress, int> subnet = QHostAddress::parseSubnet(subnetStr);
|
|
|
|
|
|
Q_FOREACH (const QHostAddress &address, info.addresses()) {
|
|
|
if (isSpecialAddress(address)) {
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if (address.isInSubnet(subnet)) {
|
|
|
isInSubNet = true;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
return engine->toScriptValue(isInSubNet);
|
|
|
} catch (const Address::Error &) {
|
|
|
return engine->toScriptValue(false);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
// dnsResolveEx(host)
|
|
|
// @returns a semi-colon delimited string containing IPv6 and IPv4 addresses
|
|
|
// for host or an empty string if host is not resolvable.
|
|
|
QScriptValue ProxyPacParser::dnsResolveEx(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
try {
|
|
|
const Address info = Address::resolve(context->argument(0).toString());
|
|
|
|
|
|
QStringList addressList;
|
|
|
QString resolvedAddress(QLatin1String(""));
|
|
|
|
|
|
Q_FOREACH (const QHostAddress &address, info.addresses()) {
|
|
|
if (!isSpecialAddress(address)) {
|
|
|
addressList << address.toString();
|
|
|
}
|
|
|
}
|
|
|
if (!addressList.isEmpty()) {
|
|
|
resolvedAddress = addressList.join(QLatin1String(";"));
|
|
|
}
|
|
|
|
|
|
return engine->toScriptValue(resolvedAddress);
|
|
|
} catch (const Address::Error &) {
|
|
|
return engine->toScriptValue(QString(QLatin1String("")));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
// myIpAddressEx()
|
|
|
// @returns a semi-colon delimited string containing all IP addresses for localhost (IPv6 and/or IPv4),
|
|
|
// or an empty string if unable to resolve localhost to an IP address.
|
|
|
QScriptValue ProxyPacParser::myIpAddressEx(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount()) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
QStringList ipAddressList;
|
|
|
const QList<QHostAddress> addresses = QNetworkInterface::allAddresses();
|
|
|
Q_FOREACH (const QHostAddress address, addresses) {
|
|
|
if (!isSpecialAddress(address) && !isLocalHostAddress(address)) {
|
|
|
ipAddressList << address.toString();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
return engine->toScriptValue(ipAddressList.join(QLatin1String(";")));
|
|
|
}
|
|
|
|
|
|
// sortIpAddressList(ipAddressList)
|
|
|
// @returns a sorted ipAddressList. If both IPv4 and IPv6 addresses are present in
|
|
|
// the list. The sorted IPv6 addresses will precede the sorted IPv4 addresses.
|
|
|
QScriptValue ProxyPacParser::sortIpAddressList(QScriptContext *context, QScriptEngine *engine)
|
|
|
{
|
|
|
if (context->argumentCount() != 1) {
|
|
|
return engine->undefinedValue();
|
|
|
}
|
|
|
|
|
|
QHash<QString, QString> actualEntryMap;
|
|
|
QList<QHostAddress> ipV4List, ipV6List;
|
|
|
const QStringList ipAddressList = context->argument(0).toString().split(QLatin1Char(';'));
|
|
|
|
|
|
Q_FOREACH (const QString &ipAddress, ipAddressList) {
|
|
|
QHostAddress address(ipAddress);
|
|
|
switch (address.protocol()) {
|
|
|
case QAbstractSocket::IPv4Protocol:
|
|
|
ipV4List << address;
|
|
|
actualEntryMap.insert(address.toString(), ipAddress);
|
|
|
break;
|
|
|
case QAbstractSocket::IPv6Protocol:
|
|
|
ipV6List << address;
|
|
|
actualEntryMap.insert(address.toString(), ipAddress);
|
|
|
break;
|
|
|
default:
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
QString sortedAddress(QLatin1String(""));
|
|
|
|
|
|
if (!ipV6List.isEmpty()) {
|
|
|
qSort(ipV6List.begin(), ipV6List.end(), addressLessThanComparison);
|
|
|
sortedAddress += addressListToString(ipV6List, actualEntryMap);
|
|
|
}
|
|
|
|
|
|
if (!ipV4List.isEmpty()) {
|
|
|
qSort(ipV4List.begin(), ipV4List.end(), addressLessThanComparison);
|
|
|
if (!sortedAddress.isEmpty()) {
|
|
|
sortedAddress += QLatin1Char(';');
|
|
|
}
|
|
|
sortedAddress += addressListToString(ipV4List, actualEntryMap);
|
|
|
}
|
|
|
|
|
|
return engine->toScriptValue(sortedAddress);
|
|
|
|
|
|
}
|
|
|
|