| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.metron.stellar.dsl.functions; |
| |
| import com.google.common.base.Joiner; |
| import com.google.common.base.Splitter; |
| import com.google.common.collect.Iterables; |
| import com.google.common.net.InternetDomainName; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.commons.net.util.SubnetUtils; |
| import org.apache.metron.stellar.dsl.BaseStellarFunction; |
| import org.apache.metron.stellar.dsl.Stellar; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.List; |
| |
| public class NetworkFunctions { |
| @Stellar(name="IN_SUBNET" |
| ,description = "Returns true if an IP is within a subnet range." |
| ,params = { |
| "ip - The IP address in string form" |
| ,"cidr+ - One or more IP ranges specified in CIDR notation (for example 192.168.0.0/24)" |
| } |
| ,returns = "True if the IP address is within at least one of the network ranges and false if otherwise" |
| ) |
| public static class InSubnet extends BaseStellarFunction { |
| |
| @Override |
| public Object apply(List<Object> list) { |
| if(list.size() < 2) { |
| throw new IllegalStateException("IN_SUBNET expects at least two args: [ip, cidr1, cidr2, ...]" |
| + " where cidr is the subnet mask in cidr form" |
| ); |
| } |
| String ip = (String) list.get(0); |
| if(ip == null) { |
| return false; |
| } |
| boolean inSubnet = false; |
| for(int i = 1;i < list.size() && !inSubnet;++i) { |
| String cidr = (String) list.get(i); |
| if(cidr == null) { |
| continue; |
| } |
| inSubnet |= new SubnetUtils(cidr).getInfo().isInRange(ip); |
| } |
| |
| return inSubnet; |
| } |
| } |
| |
| @Stellar(name="REMOVE_SUBDOMAINS" |
| ,namespace = "DOMAIN" |
| ,description = "Removes the subdomains from a domain." |
| , params = { |
| "domain - Fully qualified domain name" |
| } |
| , returns = "The domain without the subdomains. " + |
| "(for example, DOMAIN_REMOVE_SUBDOMAINS('mail.yahoo.com') yields 'yahoo.com')" |
| ) |
| public static class RemoveSubdomains extends BaseStellarFunction { |
| |
| @Override |
| public Object apply(List<Object> objects) { |
| if(objects.isEmpty()) { |
| return null; |
| } |
| Object dnObj = objects.get(0); |
| InternetDomainName idn = toDomainName(dnObj); |
| if(idn != null) { |
| String dn = dnObj.toString(); |
| String tld = extractTld(idn, dn); |
| if(!StringUtils.isEmpty(dn)) { |
| String suffix = safeSubstring(dn, 0, dn.length() - tld.length()); |
| String hostnameWithoutTLD = safeSubstring(suffix, 0, suffix.length() - 1); |
| if(hostnameWithoutTLD == null) { |
| return dn; |
| } |
| String hostnameWithoutSubsAndTLD = Iterables.getLast(Splitter.on(".").split(hostnameWithoutTLD), null); |
| if(hostnameWithoutSubsAndTLD == null) { |
| return null; |
| } |
| return hostnameWithoutSubsAndTLD + "." + tld; |
| } |
| } |
| return null; |
| } |
| } |
| |
| @Stellar(name="REMOVE_TLD" |
| ,namespace = "DOMAIN" |
| ,description = "Removes the top level domain (TLD) suffix from a domain." |
| , params = { |
| "domain - Fully qualified domain name" |
| } |
| , returns = "The domain without the TLD. " + |
| "(for example, DOMAIN_REMOVE_TLD('mail.yahoo.co.uk') yields 'mail.yahoo')" |
| ) |
| public static class RemoveTLD extends BaseStellarFunction { |
| @Override |
| public Object apply(List<Object> objects) { |
| Object dnObj = objects.get(0); |
| InternetDomainName idn = toDomainName(dnObj); |
| if(idn != null) { |
| String dn = dnObj.toString(); |
| String tld = extractTld(idn, dn); |
| String suffix = safeSubstring(dn, 0, dn.length() - tld.length()); |
| if(StringUtils.isEmpty(suffix)) { |
| return suffix; |
| } |
| else { |
| return suffix.substring(0, suffix.length() - 1); |
| } |
| } |
| return null; |
| } |
| } |
| |
| @Stellar(name="TO_TLD" |
| ,namespace = "DOMAIN" |
| ,description = "Extracts the top level domain from a domain" |
| , params = { |
| "domain - Fully qualified domain name" |
| } |
| , returns = "The TLD of the domain. " + |
| "(for example, DOMAIN_TO_TLD('mail.yahoo.co.uk') yields 'co.uk')" |
| ) |
| public static class ExtractTLD extends BaseStellarFunction { |
| @Override |
| public Object apply(List<Object> objects) { |
| Object dnObj = objects.get(0); |
| InternetDomainName idn = toDomainName(dnObj); |
| return extractTld(idn, dnObj + ""); |
| } |
| } |
| |
| @Stellar(name="TO_PORT" |
| ,namespace="URL" |
| ,description = "Extract the port from a URL. " + |
| "If the port is not explicitly stated in the URL, then an implicit port is inferred based on the protocol." |
| , params = { |
| "url - URL in string form" |
| } |
| , returns = "The port used in the URL as an integer (for example, URL_TO_PORT('http://www.yahoo.com/foo') would yield 80)" |
| ) |
| public static class URLToPort extends BaseStellarFunction { |
| @Override |
| public Object apply(List<Object> objects) { |
| URL url = toUrl(objects.get(0)); |
| if(url == null) { |
| return null; |
| } |
| int port = url.getPort(); |
| return port >= 0?port:url.getDefaultPort(); |
| } |
| } |
| |
| @Stellar(name="TO_PATH" |
| ,namespace="URL" |
| ,description = "Extract the path from a URL." |
| , params = { |
| "url - URL in String form" |
| } |
| , returns = "The path from the URL as a String. e.g. URL_TO_PATH('http://www.yahoo.com/foo') would yield 'foo'") |
| public static class URLToPath extends BaseStellarFunction { |
| @Override |
| public Object apply(List<Object> objects) { |
| URL url = toUrl(objects.get(0)); |
| return url == null?null:url.getPath(); |
| } |
| } |
| |
| @Stellar(name="TO_HOST" |
| ,namespace="URL" |
| ,description = "Extract the hostname from a URL." |
| , params = { |
| "url - URL in String form" |
| } |
| , returns = "The hostname from the URL as a String. e.g. URL_TO_HOST('http://www.yahoo.com/foo') would yield 'www.yahoo.com'" |
| ) |
| public static class URLToHost extends BaseStellarFunction { |
| |
| @Override |
| public Object apply(List<Object> objects) { |
| URL url = toUrl(objects.get(0)); |
| return url == null?null:url.getHost(); |
| } |
| } |
| |
| @Stellar(name="TO_PROTOCOL" |
| ,namespace="URL" |
| ,description = "Extract the protocol from a URL." |
| , params = { |
| "url - URL in String form" |
| } |
| , returns = "The protocol from the URL as a String. e.g. URL_TO_PROTOCOL('http://www.yahoo.com/foo') would yield 'http'") |
| public static class URLToProtocol extends BaseStellarFunction { |
| |
| @Override |
| public Object apply(List<Object> objects) { |
| URL url = toUrl(objects.get(0)); |
| return url == null?null:url.getProtocol(); |
| } |
| } |
| |
| /** |
| * Extract the TLD. If the domain is a normal domain, then we can handle the TLD via the InternetDomainName object. |
| * If it is not, then we default to returning the last segment after the final '.' |
| * @param idn |
| * @param dn |
| * @return The TLD of the domain |
| */ |
| private static String extractTld(InternetDomainName idn, String dn) { |
| |
| if(idn != null && idn.hasPublicSuffix()) { |
| String ret = idn.publicSuffix().toString(); |
| if(ret.startsWith("InternetDomainName")) { |
| return Joiner.on(".").join(idn.publicSuffix().parts()); |
| } |
| else { |
| return ret; |
| } |
| } |
| else if(dn != null) { |
| StringBuffer tld = new StringBuffer(""); |
| for(int idx = dn.length() -1;idx >= 0;idx--) { |
| char c = dn.charAt(idx); |
| if(c == '.') { |
| break; |
| } |
| else { |
| tld.append(dn.charAt(idx)); |
| } |
| } |
| return tld.reverse().toString(); |
| } |
| else { |
| return null; |
| } |
| } |
| |
| private static String safeSubstring(String val, int start, int end) { |
| if(!StringUtils.isEmpty(val)) { |
| return val.substring(start, end); |
| } |
| return null; |
| } |
| |
| private static InternetDomainName toDomainName(Object dnObj) { |
| if(dnObj != null) { |
| if(dnObj instanceof String) { |
| String dn = dnObj.toString(); |
| try { |
| return InternetDomainName.from(dn); |
| } |
| catch(IllegalArgumentException iae) { |
| return null; |
| } |
| } |
| else { |
| throw new IllegalArgumentException(dnObj + " is not a string and therefore also not a domain."); |
| } |
| } |
| return null; |
| } |
| |
| private static URL toUrl(Object urlObj) { |
| if(urlObj == null) { |
| return null; |
| } |
| if(urlObj instanceof String) { |
| String url = urlObj.toString(); |
| try { |
| return new URL(url); |
| } catch (MalformedURLException e) { |
| return null; |
| } |
| } |
| else { |
| throw new IllegalArgumentException(urlObj + " is not a string and therefore also not a URL."); |
| } |
| } |
| } |